#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DHTesp.h>
#include <WiFi.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1//We are using the same reset as the esp32 board
#define SCREEN_ADDRESS 0x3c
#define BUZZER 5
#define LED_1 15
#define PB_CANCEL 34
#define PB_OK 32
#define PB_UP 33
#define PB_DOWN 35
#define DHTPIN 12
#define NTP_SERVER "pool.ntp.org"
int UTC_OFFSET;
int time_zone_hours;
int time_zone_minutes;
#define UTC_OFFSET_DST 0
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
//calling a constructor for the Adafruit_SSD1306 class to create an instance of it instance in here is display
DHTesp dhtSensor;
//we have to define time variables as global variables .Because they are used in everywhere in the code
int days = 0;
int hours = 0;
int minutes = 0;
int seconds = 0;
bool alarm_enabled = true;//to initialize all alarms
int n_alarms = 3;//to keep track of number of alarms
int alarm_hours [] = {17, 17,17}; //to keep track of hours of the alarm
int alarm_minutes [] = {35, 34,36}; //to keep track of minutes of the alarm
bool alarm_triggered [] = {false, false,false}; /*if a user press the stop button in the alarm
alarm must be stopped for the remaining seconds of that minute this will check that
user has pressed the stop alarm button*/
int n_notes = 8;
int C = 262;//defining frequincies of the notes
int D = 294;
int E = 330;
int F = 349;
int G = 392;
int A = 440;
int B = 494;
int C_H = 523;
int notes [] = {C, D, E, F, G, A, B, C_H};
int current_mode = 0;
int max_modes = 5;
String modes [] = {"1 - Set Time Zone", "2- Set Alarm 1", "3 - Set Alarm 2","4 - Set Alarm 3","5 - Disable Alarm"};
void setup() {
//defining each pins
pinMode(BUZZER, OUTPUT);
pinMode(LED_1, OUTPUT);
pinMode(PB_CANCEL, INPUT);
pinMode(PB_OK, INPUT);
pinMode(PB_UP, INPUT);
pinMode(PB_DOWN, INPUT);
dhtSensor.setup(DHTPIN, DHTesp::DHT22);
Serial.begin(115200);//initializing serial communication
if (! display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));//F means we are storing this print line in flash memory not in the ram because ram is limited in esp32
for (;;); //this is an infinite for loop loop,in previous cases we have to specify the conditions between those semi colons but here they are not specified bcz of that this is a infinite for loop
}
//turn on the display
display.display();
delay(500);
WiFi.begin("Wokwi-GUEST", "", 6);//this will initialize the wifi connection
while (WiFi.status() != WL_CONNECTED) {
delay(250);
display.clearDisplay();
print_line("Connecting to WIFI",0,0,2);
}
display.clearDisplay();
print_line("Connected to WIFI",0,0,2);
configTime(UTC_OFFSET, UTC_OFFSET_DST, NTP_SERVER);
//clear the display
display.clearDisplay();
print_line("Welcome to medi box", 10, 20, 2);
delay(500);
display.clearDisplay();
}
void loop() {
// code inside here will run repeatedly
update_time_with_check_alarm();
if (digitalRead(PB_OK) == LOW) {
delay(200);//to debounce the push button
go_to_menu();
}
check_temp();
}
void print_line(String text, int column, int row, int text_size) {//creating a separate function for printing things (this will reduce number of lines in the code)
display.setTextSize(text_size);
display.setTextColor(SSD1306_WHITE);
display.setCursor(column, row); //specifies where the cursor has to be when starting the print(0,0) are x and y coordinates
display.println(text);
display.display();
}
void print_time_now(void) {//printing the current time
display.clearDisplay();
print_line(String(days), 0, 0, 2);//converting int value into String using casting
print_line(":", 20, 0, 2);
print_line(String(hours), 30, 0, 2);
print_line(":", 50, 0, 2);
print_line(String(minutes), 60, 0, 2);
print_line(":", 80, 0, 2);
print_line(String(seconds), 90, 0, 2);
}
void update_time() {
struct tm timeinfo;
getLocalTime(&timeinfo);//this will get the local time and it will assign it to the timeinfo variable
char timeHour[3];
strftime(timeHour,3,"%H",&timeinfo);//gives hours as a string and stores it in timeHour variable
hours = atoi(timeHour);//converts string into integer
char timeMinute[3];
strftime(timeMinute,3,"%M",&timeinfo);//gives Minutes as a string and stores it in timeMinute variable
minutes = atoi(timeMinute);//converts string into integer
char timeSecond[3];
strftime(timeSecond,3,"%S",&timeinfo);//gives Seconds as a string and stores it in timeSecond variable
seconds = atoi(timeSecond);//converts string into integer
char timeDay[3];
strftime(timeDay,3,"%d",&timeinfo);//gives Days as a string and stores it in timeDay variable
days = atoi(timeDay);//converts string into integer
}
void ring_alarm() {
display.clearDisplay();
print_line("MEDICINE TIME ! ", 0, 0, 2);
digitalWrite(LED_1, HIGH);
bool break_happened = false;//to stop the buzzer,checking if the cancel button is pressed this is used to stop the while loop
/*this condition is used to break the while loop if the user released the cancel button very
quickly after pressing it digitalRead(PB_CANCEL) == HIGH this line can become true to break
the while loop we introduce this condition*/
//RINGING THE BUZZER
while (break_happened == false && digitalRead(PB_CANCEL) == HIGH) {
for (int i = 0; i < n_notes; i++) {
if (digitalRead(PB_CANCEL) == LOW) {//checking if the cancel button is pressed to stop the alarm
delay(200);//to reduce the bouncing of the push button
break_happened = true;
break;
}
tone(BUZZER, notes[i]);
delay(500);
noTone(BUZZER);
delay(2);
}
}
digitalWrite(LED_1, LOW);
display.clearDisplay();
}
void update_time_with_check_alarm(void) {
update_time();
print_time_now();
if (alarm_enabled == true ) {//checking if the alarms are enabled
for (int i = 0; i < n_alarms; i++) {
if (alarm_triggered[i] == false && alarm_hours[i] == hours && alarm_minutes[i] == minutes) {
/*this if condition will check that if the user has pressed the stop button
if not it will check if the current time is equal to the alarm time if that is
equal this will ring the alarm*/
ring_alarm();
alarm_triggered[i] = true;
}
}
}
}
int wait_for_button_press() {//returning what button is pressed
while (true) {
if (digitalRead(PB_UP) == LOW) {
delay(2000);
return PB_UP;
}
else if (digitalRead(PB_DOWN) == LOW) {
delay(2000);
return PB_DOWN;
}
else if (digitalRead(PB_OK) == LOW) {
delay(2000);
return PB_OK;
}
else if (digitalRead(PB_CANCEL) == LOW) {
delay(2000);
return PB_CANCEL;
}
update_time();
}
}
void go_to_menu() {
while (digitalRead(PB_CANCEL) == HIGH) {//this loop runs until the cancel button is pressed
display.clearDisplay();
print_line(modes[current_mode], 0, 0, 2); //display current mode
int pressed = wait_for_button_press();//getting the return value of function wait_for_button_press() and assigning it here
if (pressed == PB_UP) {
current_mode += 1;
current_mode = current_mode % max_modes;//current modes has equalled the max modes we have to make the value of current mode back to zero again
}
else if (pressed == PB_DOWN) {
current_mode -= 1;
if (current_mode < 0) {
current_mode = max_modes - 1; //modes are 0,1,2,3,4
//when current mode goes below zero increasing it to max_modes-1
}
}
else if (pressed == PB_OK) {
delay(200);
run_mode(current_mode);//running the currently selected mode
}
else if (pressed == PB_CANCEL) {//leaving the menu
delay(200);
break;
}
}
}
void set_time_zone() {
int temp_hour =0 ;//keeping track of the hours variable that the user inputs
//if user does not press ok this temp_hour value will not be assigned to hours value
int temp_minute =0 ;
while (true) {
display.clearDisplay();
print_line("Enter time zone hour: " + String(temp_hour), 0, 0, 2);
int pressed = wait_for_button_press();
//time zone value range is from -12 to +14
if (pressed == PB_UP) {
delay(200);
temp_hour += 1;
if (temp_hour == 15){
temp_hour = -12;
}
}
else if (pressed == PB_DOWN) {
temp_hour -= 1;
if (temp_hour==-13) {
temp_hour = 14;
}
}
else if (pressed == PB_OK) {
delay(200);
time_zone_hours = temp_hour;
break;
}
else if (pressed == PB_CANCEL) {
delay(200);
break;
}
}
while (true) {
display.clearDisplay();
print_line("Enter time zone minutes: " + String(temp_minute), 0, 0, 2);
int pressed = wait_for_button_press();
if (pressed == PB_UP) {
delay(200);
temp_minute += 15;//time zone minutes changes in multiples of 15
temp_minute = temp_minute % 60;
}
else if (pressed == PB_DOWN) {
temp_minute -= 15;
if (temp_minute < 0) {
temp_minute = 45;
}
}
else if (pressed == PB_OK) {
delay(200);
time_zone_minutes = temp_minute;
break;
}
else if (pressed == PB_CANCEL) {
delay(200);
break;
}
}
setOFFSET(time_zone_hours,time_zone_minutes);
configTime(UTC_OFFSET, UTC_OFFSET_DST, NTP_SERVER);
display.clearDisplay();
print_line("Time is Set", 0, 0, 2);
delay(1000);
}
void set_alarm (int alarm) {
int temp_hour = alarm_hours[alarm] ;//setting the hours value of the alarm
while (true) {
display.clearDisplay();
print_line("Enter hour: " + String(temp_hour), 0, 0, 2);
int pressed = wait_for_button_press();
if (pressed == PB_UP) {
delay(200);
temp_hour += 1;
temp_hour = temp_hour % 24;
}
else if (pressed == PB_DOWN) {
temp_hour -= 1;
if (temp_hour < 0) {
temp_hour = 23;//modes are 0,1,2,3
}
}
else if (pressed == PB_OK) {
delay(200);
alarm_hours[alarm] = temp_hour;//assigning the value of temporary variable to alarm hours
break;
}
else if (pressed == PB_CANCEL) {
delay(200);
break;
}
}
int temp_minute = alarm_minutes[alarm] ;
while (true) {
display.clearDisplay();
print_line("Enter minute: " + String(temp_minute), 0, 0, 2);
int pressed = wait_for_button_press();
if (pressed == PB_UP) {
delay(200);
temp_minute += 1;
temp_minute = temp_minute % 60;
}
else if (pressed == PB_DOWN) {
temp_minute -= 1;
if (temp_minute < 0) {
temp_minute = 59;
}
}
else if (pressed == PB_OK) {
delay(200);
alarm_minutes[alarm] = temp_minute;
break;
}
else if (pressed == PB_CANCEL) {
delay(200);
break;
}
}
display.clearDisplay();
print_line("Alarm is set", 0, 0, 2);
delay(1000);
}
void run_mode(int mode) {//modes are 0,1,2,3,4
if (mode == 0) {
set_time_zone();
}
if (mode == 1 || mode == 2 || mode == 3) {
set_alarm(mode - 1);//current mode is 1 or 2 by substracting one from it we can access set alarm function with input parameter 0 or 1
}
else if (mode == 4) {
disable_alarms();
}
}
void check_temp() {
TempAndHumidity data = dhtSensor.getTempAndHumidity();//creating a variable named data of type TempAndHumidity
if (data.temperature > 32) {
display.clearDisplay();
print_line("TEMP HIGH", 0, 40, 1);
}
if (data.temperature < 26) {
display.clearDisplay();
print_line("TEMP LOW", 0, 40, 1);
}
if (data.humidity > 80) {
display.clearDisplay();
print_line("HUMIDITY HIGH", 0, 50, 1);
}
if (data.humidity < 60) {
display.clearDisplay();
print_line("HUMIDITY LOW", 0, 50, 1);
}
}
void setOFFSET(int hour,int minute){
if(hour<0){
UTC_OFFSET=3600*hour-60*minute;
}
else{
UTC_OFFSET=3600*hour+60*minute;
}
}
void disable_alarms() {
alarm_enabled = false;// set alarm_enabled to false ,this will disable all the alarms
display.clearDisplay();
print_line(" All alarms are disabled", 0, 0, 2);
delay(1000);
}