ESP Alarm Clock With Remote Snooze Button (alarm Only Turns Off When Far Enough Away)

by choimik26 in Circuits > Arduino

44 Views, 0 Favorites, 0 Comments

ESP Alarm Clock With Remote Snooze Button (alarm Only Turns Off When Far Enough Away)

IMG_3889.jpg
IMG_1385.jpg

Welcome to this ESP Alarm Clock Tutorial. Follow the steps below to learn how to code and wire the LCD and ESP together to create an internet alarm clock which tracks time on its own RTC module and automatically sends requests when internet is available to update its time. In addition, the alarm clock can be programmed to keep an alarm at a specified time and will only stop once a remote button is pressed which is a set distance away from the alarm clock. It is meant to make sure you actually get out of bed in the morning because pressing the button will only turn off when sufficiently far enough away

Supplies

LCD 16x2 Display

2x ESP32

Male to Female Connectors (a lot)

Male to Male Connectors

2x Mini Breadboard

DS 3231M RTC Module

CR 2032 Coin Battery

2x Micro USB Cable Connector

3x Piezo Buzzer

Connecting ESP to LCD

IMG_1385.jpg
IMG_3882.jpg

First, you will need to connect the ESP pins to the LCD pins.


// Create An LCD Object. Signals: [ RS, EN, D4, D5, D6, D7 ]

LiquidCrystal lcd(13, 12, 14, 27, 26, 25);


Notice how in the code snippet above we have assigned pins 13, 12, 14, 27, 26, 25 to respective pins of the LCD object to the ESP. These are the corresponding pins you will need to attach the female to male connectors in order for the code snippet above to work correctly. I suggest you follow the pin numbering above as it will be easier to use for the future. After attaching all these pins remember to attach the ground and 5V connectors to the breadboard to create a power source for the following pins. Finally, make sure to attach the potentiometer to vary the LCD screen's brightness.


I personally followed this tutorial making small adjustments with how the ground and VIN was hooked up; however, if you follow the connections to the tea from this tutorial by DeepBlueMbedded the code I wrote should be compatible with the setup in the tutorial. The only difference between the wiring is I directly connected with male to female connectors from the ESP to the LCD without a breadboard, and only used a small separate breadboard to power a rail for the various ground and VIN connections needed.

https://deepbluembedded.com/esp32-lcd-display-16x2-without-i2c-arduino/


Connect the LCD ESP to the RTC Module

IMG_3883.jpg
IMG_3884.jpg
IMG_3885.jpg
  1. Connect SCL to D22 with Female to Female Connector
  2. Connect SDA to D21 with Female to Female Connector
  3. Connect VCC to VIN powered rail with Male to Female Connector
  4. Connect GND to GND powered rail with Male to Female Connector
  5. Insert CR 2032 Coin Battery into DS3231M RTC Module


Before you freak out when seeing the breadboard picture (it is the breadboard containing all the GND and VIN connections between the LCD, RTC Module and Piezo Buzzers), all you need to know is that the VIN and GND were rails defined along the left and right side of the breadboard with the capability to power the RTC module circuit by connecting the RTC to the corresponding VIN and GND rails.

Connect the LCD ESP to the Piezo Buzzer

IMG_3885.jpg

Connect pin D32 to a rail (this will be your positive rail).

Connect pin GND (the GND next to the 3.3V pin not the one next to VIN) to a rail. This rail will be your ground rail.

Connect the positive end of the piezo buzzers to the positive rail and negative end to the ground rail. Rinse and repeat for as many piezo buzzers as you would like.


You are now done wiring the setup for the ESP which controls the LCD, buzzers and RTC module!

Wire the ESP Button Remote

IMG_3881.jpg

Connect the second ESP to the button configuration shown above. The configuration is a simple pull up button with the GPIO pin from the ESP being declared a INPUT_PULLUP so that a pullup resistor is not required. In total, all you have to connect is to place a button on a bread board and attach a ground pin with a female to male connector from the ESP to the button and do the same with pin D13 to the other leg of the button.


ESP to Breadboard Connections:

D13 -> one leg of button on same side of breadboard

GND -> other leg of button on the same side of breadboard

Setup Arduino IDE for ESP

esp libraries.png
rtc library.png

Before we can code the ESPs we will need some supporting libraries mainly esp32 by espressif and DS3231 by Andrew Wickert. Esp32 will allow us to upload code from the Arduino IDE to the esp and DS3231 is a library to control the RTC module.

Code the LCD ESP

esp pic 1.png

You can copy and paste the code snippet below to get the ESP to connect to WiFi correctly and start updating time from the time servers online. Make sure to change the WiFi name and password to connect properly to your home network. When you are done copying and pasting make sure to have the correct setup to push the code into bytecode for your ESP. The code copy and pasted below will display time on the LCD, update the time with the time servers, reprogram time to the RTC module and buzz for an alarm at 7am (this time can be changed by changing defaultHour and defaultMinute in the code snippets below). You may also have to change the UTCOffset_sec variable to match your timezone (it is already set into ET).


CODE BELOW:


#include <LiquidCrystal.h>
#include <WiFi.h>
#include "time.h"
#include "sntp.h"
#include <iostream>
#include <vector>
#include <DS3231.h>
#include <esp_now.h>
#include <esp_wifi.h>

//Type Network Name and Password for WIFI_NETWORK and WIFI_PASSWORD
#define WIFI_NETWORK ""
#define WIFI_PASSWORD ""
#define WIFI_TIMEOUT_MS 20000

//DO NOT CHANGE THIS NETWORK AND PASSWORD (HARD WRITTEN BETWEEN BOTH ESPs)
#define AP_WIFI_NETWORK "AccessPoint"
#define AP_WIFI_PASSWORD "password"

// Create An LCD Object. Signals: [ RS, EN, D4, D5, D6, D7 ]
LiquidCrystal lcd(13, 12, 14, 27, 26, 25);

const int buzzerPin = 32;

const char* ntpServer1 = "pool.ntp.org";
const char* ntpServer2 = "time.nist.gov";
//Time difference between UTC and ET in seconds
const long UTCOffset_sec = -18000;
//The one hour on daylight savings time in seconds
const int daylightOffset_sec = 3600;
//Place a leap year offset for every Feb 29

unsigned long fetchElapsed = 0;

//struct to store time
struct tm timeinfo;
struct tm* timeinfoPtr = &timeinfo;

struct Alarm{
//value from 0-23
int hour;
//value from 0-59
int minute;
//value from 0-59
int second;
//starts on monday and ends on sundays
boolean days[7];

Alarm(int hour, int minute, int second, boolean days[7]) : hour(hour), minute(minute), second(second), days(days){}
};

int defaultHour = 7;
int defaultMinute = 0;
int defaultSecond = 0;
boolean defaultDays[7] = {true, true, true, true, true, false, false};

Alarm morningAlarm(defaultHour, defaultMinute, defaultSecond, defaultDays);

//Create RTC object
DS3231 myRTC;

//Create esp peer struct object
uint8_t broadcastAddress[] = {0x34, 0x94, 0x54, 0x47, 0x1b, 0xf9};

typedef struct struct_message {
double RSSI;
} struct_message;

struct_message incomingMessage;

esp_now_peer_info_t peerInfo;



void connectToWiFi(){
lcd.clear();
lcd.println("Connecting to WiFi");
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_NETWORK, WIFI_PASSWORD);

unsigned long startAttemptTime = millis();


while(WiFi.status() != WL_CONNECTED && millis() - startAttemptTime < WIFI_TIMEOUT_MS){
Serial.print(".");
delay(100);
}

if(WiFi.status() != WL_CONNECTED){
lcd.setCursor(0, 1);
lcd.println("Failed");
Serial.println("Failed");
//either reboot esp or deep sleep
}
else {
Serial.println("Connected");
Serial.println(WiFi.localIP());

//Print to lcd
lcd.clear();
lcd.print("Connected");
lcd.setCursor(0, 1);
lcd.print(WiFi.localIP());
}
}

void printLocalTime()
{
//Display Date & Time
lcd.clear();
lcd.print(timeinfoPtr, "%b %d %Y"); //November 22 2022
lcd.setCursor(0,1);
lcd.print(timeinfoPtr, "%a, %H:%M:%S"); //Tuesday 10:30:05
}

//Function call for first fetching of time when alarm clock starts
void fetchTime(){
configTime(UTCOffset_sec, daylightOffset_sec, ntpServer1, ntpServer2);
getLocalTime(&timeinfo);
}

void updateRTCTime(){
//Update time by fetching from time servers
fetchTime();
//Set RTC Module to time fetched
myRTC.setYear(timeinfoPtr->tm_year);
myRTC.setMonth(timeinfoPtr->tm_mon);
myRTC.setDate(timeinfoPtr->tm_mday);
myRTC.setDoW(timeinfoPtr->tm_wday);
myRTC.setHour(timeinfoPtr->tm_hour);
myRTC.setMinute(timeinfoPtr->tm_min);
myRTC.setSecond(timeinfoPtr->tm_sec+1);
}

void setStructToRTC(){
//Sets RTC stored time into time struct
bool h12;
bool hPM;
bool CenturyBit;
timeinfoPtr->tm_year = myRTC.getYear();
timeinfoPtr->tm_mon = myRTC.getMonth(CenturyBit);
timeinfoPtr->tm_mday = myRTC.getDate();
timeinfoPtr->tm_wday = myRTC.getDoW();
timeinfoPtr->tm_hour = myRTC.getHour(h12, hPM);
timeinfoPtr->tm_min = myRTC.getMinute();
timeinfoPtr->tm_sec = myRTC.getSecond();
mktime(&timeinfo);
}

bool dataRecv = false;
int32_t RSSI = 0;
bool connectAPWiFi = false;


// Callback when data is received
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
Serial.println("Data Received ");
dataRecv = true;
connectAPWiFi = true;
}

void setupPeerConnection(){
WiFi.mode(WIFI_STA);
// Init ESP-NOW
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}


// Register peer
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;

// Add peer
if (esp_now_add_peer(&peerInfo) != ESP_OK){
Serial.println("Failed to add peer");
return;
}
// Once ESPNow is successfully Init, we will register for Send CB to
// get the status of Trasnmitted packet
//esp_now_register_send_cb(OnDataSent);
// Register for a callback function that will be called when data is received
esp_now_register_recv_cb(esp_now_recv_cb_t(OnDataRecv));
}


void setup() {
Serial.begin(115200);
Serial.println("Serial Connected Created");
// Initialize The LCD. Parameters: [ Columns, Rows ]
lcd.begin(16, 2);
// Clears The LCD Display
lcd.clear()

//connect to WiFi
connectToWiFi();

//Set up RTC Module
Wire.begin();
bool mode12 = false; // use 24-hour clock mode
myRTC.setClockMode(mode12);

//fetch time server time and update time to rtc module
updateRTCTime();

setStructToRTC();
printLocalTime();

pinMode(buzzerPin, OUTPUT);

// Once ESPNow is successfully Init, we will register for Send CB to
// get the status of Trasnmitted packet
WiFi.disconnect(true);
delay(100);
esp_wifi_stop();
esp_wifi_deinit();
delay(100);

setupPeerConnection();
}


void loop() {
delay(250);
if(connectAPWiFi){
WiFi.begin(AP_WIFI_NETWORK, AP_WIFI_PASSWORD);
delay(500);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(50);
}
Serial.println("\nConnected!");


RSSI = WiFi.RSSI();
Serial.print("RSSI VALUE EXISTS");
Serial.printf("\n%ld\n", (long)RSSI);


WiFi.disconnect();
WiFi.mode(WIFI_STA);
connectAPWiFi = false;
}
if(morningAlarm.hour == timeinfoPtr->tm_hour && morningAlarm.minute == timeinfoPtr->tm_min && morningAlarm.second == timeinfoPtr->tm_sec){
while((long)RSSI >= -75){
if(connectAPWiFi){
WiFi.begin(AP_WIFI_NETWORK, AP_WIFI_PASSWORD);
delay(500);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(50);
}
Serial.println("\nConnected!");


RSSI = WiFi.RSSI();
Serial.print("RSSI VALUE EXISTS");
Serial.printf("\n%ld\n", (long)RSSI);


WiFi.disconnect();
WiFi.mode(WIFI_STA);
connectAPWiFi = false;
}
delay(125);
setStructToRTC();
printLocalTime();
tone(buzzerPin, 500, 250);
setStructToRTC();
printLocalTime();
for(int i = 0; i < 2; i++){
delay(125);
setStructToRTC();
printLocalTime();
}
}
RSSI = 0;
dataRecv = false;
}
setStructToRTC();
printLocalTime();

}



Code the Remote Button ESP

Screenshot 2025-05-21 135606.png

The code below will contact the other Alarm ESP to turn off the piezo buzzers if the remote is far enough away and while the alarm is on. The code basically switches between a peer to peer connection with ESP NOW protocol using a stationary mode and then switches the Remote Button ESP into a soft access point from which the other ESP once finished with its callback will connect to and calculate the RSSI value on its end.


CODE BELOW


#include <esp_now.h>
#include <esp_wifi.h>
#include <WiFi.h>

esp_now_peer_info_t peerInfo;
uint8_t broadcastAddress[] = { 0xe4, 0x65, 0xb8, 0x76, 0x84, 0x74 };

typedef struct struct_message {
int32_t RSSI;
} struct_message;

struct_message sendMessage;

const int buttonInput = 13;


void setupPeerConnection() {
WiFi.mode(WIFI_STA);

if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}

// Register peer
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;

// Add peer
if (esp_now_add_peer(&peerInfo) != ESP_OK) {
Serial.println("Failed to add peer");
return;
} else {
Serial.println("Added peer");
}
// Once ESPNow is successfully Init, we will register for Send CB to
// get the status of Trasnmitted packet
esp_now_register_send_cb(OnDataSent);
// Register for a callback function that will be called when data is received
//esp_now_register_recv_cb(esp_now_recv_cb_t(OnDataRecv));
}


void setup() {
Serial.begin(115200);
Serial.println("Serial Connected Created");
// put your setup code here, to run once:
//Setup peer connection twice so that not forget esp companion
setupPeerConnection();

pinMode(buttonInput, INPUT_PULLUP);
}


//Create AP credentials (PLS DO NOT CHANGE)
const char *ssid = "AccessPoint";
const char *password = "password";

// Callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
if (status == 0) {
Serial.print("Success");
} else {
Serial.print("Failed");
}
}

bool switchToSTA = false;

void loop() {
if(switchToSTA){
WiFi.disconnect();
WiFi.mode(WIFI_STA);
switchToSTA = false;
}
if (digitalRead(buttonInput) == LOW) {
WiFi.mode(WIFI_AP_STA);
WiFi.softAP(ssid, password);

delay(500);
sendMessage.RSSI = -1;
esp_now_send(broadcastAddress, (uint8_t *)&sendMessage, sizeof(sendMessage));

//DELAY REQUIRED FOR CODE TO WORK IDK REALLY WHY BUT WHEN I TOOK IT OUT IT DID NOT WORK
//I think its because send request needs enough time so that it can use its callback and
//then connect to wifi before the wifi is disconnected from switchToSTA
delay(5000);
//Debounce to get up to speed with change in wifi mode
delay(500);
switchToSTA = true;
}
}

Create a Housing for the Alarm Clock

IMG_3886.jpg
IMG_3887.jpg
IMG_3888.jpg
IMG_3889.jpg

Use foamcore to build a suitable housing for the electronic components of the alarm clock. You can use cardboard, foamcore or even 3d print your own alarm clock housing.

Create a Housing for the Remote

IMG_3890.jpg
IMG_3892.jpg

Use foamcore to build a suitable housing for the electronic components of the remote snooze button. You can use cardboard, foamcore or even 3d print your own alarm clock housing.

Credit to Sources