// Include libraries
#include <Wire.h>
#include <Adafruit_GFX.h> // OLED display
#include <Adafruit_SSD1306.h> // OLED display
#include <DHTesp.h> // DHT22 sensor
#include <WiFi.h> // Wi-Fi network.
// Define OLED parameters
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
// Define connection pins
#define LED_1 12
#define Buzzer 14
#define PB_ok 35
#define PB_up 32
#define PB_down 33
#define PB_cancel 25
#define dht 26
// Define NTP clock parameters
#define NTP_SERVER "pool.ntp.org"
#define UTC_OFFSET 0
#define UTC_OFFSET_DST 0
// To control the OLED display.
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// To interact with the DHT22 sensor
DHTesp dhtSensor;
// variables for time
int hours = 0;
int minutes = 0;
int new_UTC_OFFSET = 0;
// variables for alarm
bool alarm_enabled = true;
int n_alarms = 3;
int alarm_hours[] = {0, 1, 2};
int alarm_minutes[] = {1, 10, 20};
bool alarm_triggered[] = {false, false, false};
// variables for buzzer
int n_notes = 8;
int C = 262;
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};
// variables for menu
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 all Alarms"
};
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
Serial.begin(115200);
pinMode(LED_1, OUTPUT);
pinMode(Buzzer, OUTPUT);
pinMode(PB_cancel, INPUT);
pinMode(PB_ok, INPUT);
pinMode(PB_up, INPUT);
pinMode(PB_down, INPUT);
// It specifies the pin to which the sensor is connected (DHT_PIN) and the sensor type (DHTesp::DHT22).
dhtSensor.setup(dht, DHTesp :: DHT22);
// Initializes the OLED display. If unsuccessful, an error message is printed.
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
// Adafruit boot screen
display.display();
delay(500);
// Initiate a connection to a Wi-Fi network.
WiFi.begin("Wokwi-GUEST", "", 6);
display.clearDisplay();
print_line("Connecting", 0, 0, 2);
print_line("to WIFI", 0, 20, 2);
int counter = 0;
while (WiFi.status() != WL_CONNECTED) { // While wifi not connected
print_line("-", 5 * counter, 40, 4); // Simulate a loading bar
counter += 1;
}
display.clearDisplay();
print_line("WIFI", 0, 0, 2);
print_line("Connected", 0, 20, 2);
delay(500);
// Configure the time with time zone and server.
configTime(UTC_OFFSET, UTC_OFFSET_DST, NTP_SERVER);
display.clearDisplay();
print_line("Welcome to Medibox!", 0, 15, 2);
delay(500);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() {
check_menu();
display.clearDisplay();
print_time_with_check_alarm();
check_menu(); // To increase the sensitivity of the menu button.
check_temp_humidity();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
void print_line(String text, int column, int row, int text_size) {
display.setTextSize(text_size);
display.setTextColor(SSD1306_WHITE);
display.setCursor(column, row);
display.println(text);
display.display();
}
/**************************************************************************************************/
void update_print_time() {
struct tm timeinfo;
getLocalTime(&timeinfo); // Retrieves the current time
char time_hour[3];
char time_minute[3];
char full_time[9];
strftime(time_hour, 3, "%H", &timeinfo); // String from Time
strftime(time_minute, 3, "%M", &timeinfo);
strftime(full_time, 9, "%H:%M:%S", &timeinfo);
hours = atoi(time_hour); // ASCII to integer
minutes = atoi(time_minute);
print_line(full_time, 15, 0, 2);
}
/**************************************************************************************************/
void ring_alarm() {
display. clearDisplay();
print_line("Medicine Time!", 0, 0, 2);
digitalWrite(LED_1, HIGH);
bool break_happened = false;
while (break_happened == false && digitalRead(PB_cancel) == HIGH) { // Checks whether the cancel button is pressed
for (int i = 0; i < n_notes; i++) {
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);
}
/**************************************************************************************************/
void print_time_with_check_alarm(void) {
update_print_time();
if (alarm_enabled == true) {
for (int i = 0; i < n_alarms ; i++) {
if (alarm_triggered[i] == false && hours == alarm_hours[i] && minutes == alarm_minutes[i]) {
ring_alarm();
alarm_triggered[i] = true;
}
}
}
}
/**************************************************************************************************/
void check_menu() {
if (digitalRead(PB_ok) == LOW) {
delay(200);
go_to_menu();
}
}
/**************************************************************************************************/
int button_pressed() {
while (true) {
if (digitalRead(PB_up) == LOW) {
delay(200);
return PB_up; // returns the pin number of 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;
}
}
}
/**************************************************************************************************/
void go_to_menu() {
while (true) {
display.clearDisplay();
print_line(modes[current_mode], 0, 0, 2);
int pressed = button_pressed();
if (pressed == PB_up) {
delay(200);
current_mode += 1;
if (current_mode > max_modes - 1) { // or current_mode = current_mode % max_modes
current_mode = 0;
}
}
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);
run_mode(current_mode);
}
else if (pressed == PB_cancel) {
delay(200);
current_mode = 0;
break;
}
}
}
/**************************************************************************************************/
void run_mode(int mode) { // mode = current_mode from go_to_menu
if (mode == 0) {
set_time_zone();
}
else if (mode == 1 || mode == 2 || mode == 3) {
set_alarm(mode - 1);
}
else if (mode == 4) {
alarm_enabled = false; // All alarms will be disabled
display.clearDisplay();
print_line("All Alarms Disabled", 0, 0, 2);
delay(1000);
}
}
/**************************************************************************************************/
void set_time_zone() {
int temp_hours = 0; // to change the global variable only after the setting is done
while (true) {
display.clearDisplay();
print_line("Enter UTC hours: " + String(temp_hours), 0, 0, 2);
int pressed = button_pressed();
if (pressed == PB_up) {
delay(200);
temp_hours += 1;
if (temp_hours > 14) {
temp_hours = -12;
}
}
else if (pressed == PB_down) {
delay(200);
temp_hours -= 1;
if (temp_hours < -12) {
temp_hours = 14;
}
}
else if (pressed == PB_ok) {
delay(200);
break;
}
else if (pressed == PB_cancel) {
delay(200);
break;
}
}
int temp_minutes = 0;
while (true) {
display.clearDisplay();
print_line("Enter UTC minutes : " + String(temp_minutes), 0, 0, 2);
int pressed = button_pressed(); // not needed, already declared in hours setting
if (pressed == PB_up) {
delay(200);
temp_minutes += 15; // Offset changes by 15 minutes
if (temp_minutes > 45) {
temp_minutes = 0;
}
}
else if (pressed == PB_down) {
delay(200);
temp_minutes -= 15;
if (temp_minutes < 0) {
temp_minutes = 45;
}
}
else if (pressed == PB_ok) {
delay(200);
break;
}
else if (pressed == PB_cancel) {
delay(200);
break;
}
}
if (temp_hours >= 0) {
new_UTC_OFFSET = 3600 * temp_hours + 60 * temp_minutes;
}
if (temp_hours < 0) {
new_UTC_OFFSET = 3600 * temp_hours - 60 * temp_minutes;
}
configTime(new_UTC_OFFSET, UTC_OFFSET_DST, NTP_SERVER);
display.clearDisplay();
print_line("Time Zone is set", 0, 0, 2);
delay(1000);
}
/**************************************************************************************************/
void set_alarm(int alarm) { // alarm = mode-1 = current_mode
int temp_hours = alarm_hours[alarm];
while (true) {
display.clearDisplay();
print_line("Enter the hour: " + String(temp_hours), 0, 0, 2);
int pressed = button_pressed();
if (pressed == PB_up) {
delay(200);
temp_hours += 1;
if (temp_hours > 23) { // or temp_hours = temp_hours % 24
temp_hours = 0;
}
}
else if (pressed == PB_down) {
delay(200);
temp_hours -= 1;
if (temp_hours < 0) {
temp_hours = 23;
}
}
else if (pressed == PB_ok) {
delay(200);
alarm_hours[alarm] = temp_hours;
break;
}
else if (pressed == PB_cancel) {
delay(200);
break;
}
}
int temp_minutes = alarm_minutes[alarm];
while (true) {
display.clearDisplay();
print_line("Enter the minute: " + String(temp_minutes), 0, 0, 2);
int pressed = button_pressed();
if (pressed == PB_up) {
delay(200);
temp_minutes += 1;
if (temp_minutes > 59) { // or temp_minutes = temp_minutes % 60
temp_minutes = 0;
}
}
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();
if (alarm == 0) {
print_line("Alarm 1 is set", 0, 0, 2);
}
else if (alarm == 1) {
print_line("Alarm 2 is set", 0, 0, 2);
}
else if (alarm == 2) {
print_line("Alarm 3 is set", 0, 0, 2);
}
delay(1000);
}
/**************************************************************************************************/
void check_temp_humidity() {
// The data variable is of type TempAndHumidity, which likely has separate fields for temperature and humidity within the library.
TempAndHumidity data = dhtSensor.getTempAndHumidity();
if (data.temperature > 32) {
print_line("TEMP HIGH", 35, 30, 1);
digitalWrite(LED_1, HIGH);
}
else if (data.temperature < 26) {
print_line("TEMP LOW", 35, 30, 1);
digitalWrite(LED_1, HIGH);
}
check_menu(); // To increase the sensitivity of the menu button.
if (data.humidity > 80) {
print_line("HUMIDITY HIGH", 25, 50, 1);
digitalWrite(LED_1, HIGH);
}
else if (data.humidity < 60) {
print_line("HUMIDITY LOW", 25, 50, 1);
digitalWrite(LED_1, HIGH);
}
delay(200);
check_menu(); // To increase the sensitivity of the menu button.
delay(200);
digitalWrite(LED_1, LOW);
check_menu(); // To increase the sensitivity of the menu button.
delay(200);
}