// Include libraries
// Libraries for the OLED display
#include <Wire.h> // communicatio with the device and display
#include <Adafruit_GFX.h> //This is a graphics library by Adafruit that provides a common set of graphics functions for different displays
#include <Adafruit_SSD1306.h> //This library is specific to the SSD1306 OLED display controller. It provides functions to interact with OLED
//dht sensor
#include <DHTesp.h>
// Define OLED parameters
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1 //This constant is used to define the reset pin for the OLED display. The value -1 indicates that the reset pin is not connected
#define SCREEN_ADDRESS 0x3C //This constant specifies the I2C address of the OLED display. The I2C address is used to communicate with the display over the I2C bus
// for the buzzer
#define BUZZER 5
#define LED_1 15
#define PB_cancel 34 // defining the push button
#define PB_OK 32 //push buttons for menu
#define PB_UP 33
#define PB_DOWN 35
//dht sensor pins
#define DHTPIN 12
//for wife
#define NTP_SERVER "pool.ntp.org"
#define UTC_OFFSET 0
#define UTC_OFFSET_DST 0
//wifi library
#include <WiFi.h>
// Declare objects
/*
..Adafruit_SSD1306: This is the class provided by the Adafruit_SSD1306 library. It encapsulates the functionality needed to communicate with and control SSD1306-based OLED displays.
..display: This is the name given to the object of the Adafruit_SSD1306 class
*/
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
//time related global variables
int days = 0;
int hours = 0;
int minutes = 0;
int seconds = 0;
//for the update time
unsigned long timeNow = 0;
unsigned long timeLast = 0;
//for the alarms.
bool alarm_enabled = true; // whether the alarm system is currently enabled (true) or disabled (false).
int n_alarms = 3; //number of alarms. In this case, there are two alarms specified.
int alarm_hours[] = {0, 1, 2, 3}; // An array storing the hour values for each alarm
int alarm_minutes[] = {1, 10, 20, 30}; // An array storing the minute values for each alarm
bool alarm_triggered[] = {false, false, false, false}; //An array of boolean values indicating whether each alarm has been triggered
//for the buzzer
int C = 262;
int D = 294;
int E = 330;
int F = 349;
int G = 392;
int A = 440;
int B = 194;
int C_H = 523;
int notes[] = {C, D, E, F, G, A, B, C_H};
int n_notes = 8;
int current_mode = 0;
int max_modes = 4;
String modes[] = {"1 - Set Time", "2 - Set Alarm 1", "3 - Set Alarm 2", "4 - Disable Alarm"};
void setup() {
// put your setup code here, to run once:
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(9600); //initialize the serial communication
/*
..code attempts to initialize the OLED display using the begin() method of the Adafruit_SSD1306 class
.. The SSD1306_SWITCHCAPVCC parameter indicates that the display should generate its display voltage internally from 3.3V
..If the initialization fails (returned false), it prints an error message to the Serial Monitor and enters an infinite loop
*/
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;) ;
}
// Show the display buffer on the screen. You MUST call display() after
// drawing commands to make them visible on screen!
display.display();
delay(2000);
//for wifi connection
WiFi.begin("Wokwi-GUEST", "", 6);
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 buffer
display.clearDisplay(); //here we are starting the display
print_line("Welcome to the Medi Box!", 10, 20, 1.8);
delay(2500);
display.clearDisplay(); //here we are starting the display
}
void loop() {
// put your main code here, to run repeatedly:
update_time_with_check_alarms();
if (digitalRead(PB_OK) == LOW) {
delay(200);
go_to_menu();
}
check_temp();
}
//function to print anything on the screen
void print_line(String text, int column, int row, int text_size) {
display.setTextSize(text_size); //adding a text size for the display
display.setTextColor(SSD1306_WHITE); //adding a text color
display.setCursor(column, row);
display.println(text);
display.display();
}
//function to capture time and print on to the display using the pirnt_line function
void print_time_now(void) {
display.clearDisplay();
print_line(String(days), 0, 0, 2);
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);
char timeHour[3];
strftime(timeHour,3, "%H", &timeinfo);
hours = atoi(timeHour);
char timeMinute[3];
strftime(timeMinute,3, "%M", &timeinfo);
minutes = atoi(timeMinute);
char timeSecond[3];
strftime(timeSecond,3, "%S", &timeinfo);
seconds = atoi(timeSecond);
char timeDay[3];
strftime(timeDay,3, "%d", &timeinfo);
days = atoi(timeDay);
}
void ring_alarm() {
display.clearDisplay();
print_line("MEDICINE TIME", 0, 0, 2);
digitalWrite(LED_1, HIGH);
bool break_happened = false;
//RING THE buzzer
while (break_happened == false && digitalRead(PB_cancel) == HIGH) {
for (int i = 0; i < n_notes; i++) {
//if clause is for stopping the for statement (buzzer) when the push button is pressed
//push button hasnt pressed > pin is at HIGH
//push button is pressed > pin is at LOW
if (digitalRead(PB_cancel) == LOW) {
delay(200);
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_alarms() {
update_time();
print_time_now();
if (alarm_enabled == true) {
for (int i = 0; i < n_alarms; i++) {
if (alarm_triggered[i] == false && alarm_hours[i] == hours && alarm_minutes[i] == minutes) {
ring_alarm();
alarm_triggered[i] = true; //this will solve the problem that alarm is triggered again when push button is pressed in alarm minute.
}
}
}
}
int wait_for_button_press() {
while (true) {
if (digitalRead(PB_UP) == LOW) {
delay(200);
return PB_UP;
}
else if (digitalRead(PB_DOWN) == LOW) {
delay(200);
return PB_DOWN;
}
else if (digitalRead(PB_OK) == LOW) {
delay(200);
return PB_OK;
}
else if (digitalRead(PB_cancel) == LOW) {
delay(200);
return PB_cancel;
}
update_time();
}
}
void go_to_menu() {
while (digitalRead(PB_cancel) == HIGH) {
display.clearDisplay();
print_line(modes[current_mode], 0, 0, 2);
int pressed = wait_for_button_press();
if (pressed == PB_UP) {
delay(200);
current_mode += 1;
current_mode = current_mode % max_modes;
}
else if (pressed == PB_DOWN) {
delay(200);
current_mode -= 1;
if (current_mode < 0) {
current_mode = max_modes - 1;
}
}
else if (pressed == PB_OK) {
delay(200);
Serial.println(current_mode);
run_mode(current_mode);
}
else if (pressed == PB_cancel) {
delay(200);
break;
}
}
}
void set_time() {
int temp_hour = hours;
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) {
delay(200);
temp_hour -= 1;
if (temp_hour < 0) {
temp_hour = 23;
}
}
else if (pressed == PB_OK) {
delay(200);
hours = temp_hour;
break;
}
else if (pressed == PB_cancel) {
delay(200);
break;
}
}
int temp_minutes = minutes;
while (true) {
display.clearDisplay();
print_line("Enter minutes:" + String(temp_minutes), 0, 0, 2);
int pressed = wait_for_button_press();
if (pressed == PB_UP) {
delay(200);
temp_minutes += 1;
temp_minutes = temp_minutes % 60;
}
else if (pressed == PB_DOWN) {
delay(200);
temp_minutes -= 1;
if (temp_minutes < 0) {
temp_minutes = 59;
}
}
else if (pressed == PB_OK) {
delay(200);
minutes = temp_minutes;
break;
}
else if (pressed == PB_cancel) {
delay(200);
break;
}
}
display.clearDisplay();
print_line("Time is set", 0, 0, 2);
delay(1000);
}
void set_alarm(int alarm) {
int temp_hour = alarm_hours[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) {
delay(200);
temp_hour -= 1;
if (temp_hour < 0) {
temp_hour = 23;
}
}
else if (pressed == PB_OK) {
delay(200);
alarm_hours[alarm] = temp_hour;
break;
}
else if (pressed == PB_cancel) {
delay(200);
break;
}
}
int temp_minutes = alarm_minutes[alarm];
while (true) {
display.clearDisplay();
print_line("Enter minutes:" + String(temp_minutes), 0, 0, 2);
int pressed = wait_for_button_press();
if (pressed == PB_UP) {
delay(200);
temp_minutes += 1;
temp_minutes = temp_minutes % 60;
}
else if (pressed == PB_DOWN) {
delay(200);
temp_minutes -= 1;
if (temp_minutes < 0) {
temp_minutes = 59;
}
}
else if (pressed == PB_OK) {
delay(200);
alarm_minutes[alarm] = temp_minutes;
break;
}
else if (pressed == PB_cancel) {
delay(200);
break;
}
}
display.clearDisplay();
print_line("Alarm is set", 0, 0, 2);
}
void run_mode(int mode) {
if (mode == 0) {
set_time();
}
else if (mode == 1 || mode == 2) {
set_alarm(mode - 1);
}
else if (mode == 3) {
alarm_enabled = false;
}
}
void check_temp() {
TempAndHumidity data = dhtSensor.getTempAndHumidity();
if (data.temperature > 35) {
display.clearDisplay();
print_line("TEMP HIGH", 0, 40, 1);
}
if (data.temperature < 25) {
display.clearDisplay();
print_line("TEMP LOW", 0, 40, 1);
}
if (data.humidity > 40) {
display.clearDisplay();
print_line("HUMIDITY HIGH", 0, 50, 1);
}
if (data.humidity < 20) {
display.clearDisplay();
print_line("HUMIDITY LOW", 0, 50, 1);
}
}