#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DHTesp.h>
#include <WiFi.h>
// Define OLED parameters
#define SCREEN_WIDTH 128 //OLED display width, in pixels
#define SCREEN_HEIGHT 64 //OLED display height, in pixels
#define OLED_RESET -1 //Reset pin
#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"
#define UTC_OFFSET 0
#define UTC_OFFSET_DST 0
// Declare Objects
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
DHTesp dhtSensor;
// Global variables
int days = 0;
int hours = 0;
int minutes = 0;
int seconds = 0;
// Default offset
int user_utc_offset = 0;
unsigned long timeNow = 0;
unsigned long timeLast = 0;
bool alarm_enabled = true;
int n_alarms = 0;
int alarm_hours[] = {0, 1};
int alarm_minutes[] = {1, 10};
bool alarm_triggered[] = {false, false};
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};
int current_mode = 0;
int max_modes = 5;
String modes[] = {"1- Set Time Zone", "2- Set Alarm 1", "3- Set Alarm 2", "4- View Active Alarms", "5- Disable Alarms"};
void setup() {
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);
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;); // Don't procedd, loop forever
}
//Show initial display buffer contents on the screen --
//the library initializes this with an Adafruit splash screen
display.display();
delay(500);
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();
print_line("Welcome to Medibox", 10, 20, 2);
delay(1000);
display.clearDisplay();
}
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();
}
void print_line(String text, int column, int row, int text_size) {
display.setTextSize(text_size);
display.setTextColor(SSD1306_WHITE);
display.setCursor(column, row); //(column,row )
display.println(text);
display.display();
}
void print_time_now() {
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(int alarm_index) {
display.clearDisplay();
print_line("MEDICINE TIME!", 0, 0, 2);
print_line("Snooze?", 30, 0, 2);
display.display();
digitalWrite(LED_1, HIGH);
bool break_happened = false;
//Ring the buzzer
while (break_happened == false && digitalRead(PB_CANCEL) == HIGH && digitalRead(PB_OK) == HIGH) {
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);
}
}
while (true) {
int pressed = wait_for_button_press();
if (pressed == PB_OK) {
delay(200);
alarm_minutes[alarm_index] += 5;
// Handle overflow of minutes (if it goes over 60)
if (alarm_minutes[alarm_index] >= 60) {
alarm_minutes[alarm_index] -= 60;
alarm_hours[alarm_index] = (alarm_hours[alarm_index] + 1) % 24;
}
display.clearDisplay();
print_line("Snoozed for 5 min!", 0, 0, 2);
display.display();
delay(1500);
return;
}
else if (pressed == PB_CANCEL) {
delay(200);
return;
}
}
}
void update_time_with_check_alarms(void) {
update_time();
print_time_now();
// Reset all alarms at midnight
if (hours == 0 && minutes == 0 && seconds == 0) {
for (int i = 0; i < n_alarms; i++) {
alarm_triggered[i] = false;
}
}
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(i);
alarm_triggered[i] = true;
}
}
}
}
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);
run_mode(current_mode);
}
else if (pressed == PB_CANCEL) {
delay(200);
break;
}
}
}
void set_time() {
int temp_offset_hours = user_utc_offset / 3600; // Convert stored offset to hours
int temp_offset_minutes = (user_utc_offset % 3600) / 60; // Extract minutes
// Step 1: Set UTC Offset (Hours)
while (true) {
display.clearDisplay();
print_line("UTC Offset (H): " + String(temp_offset_hours), 0, 0, 2);
int pressed = wait_for_button_press();
if (pressed == PB_UP) {
delay(200);
temp_offset_hours += 1;
}
else if (pressed == PB_DOWN) {
delay(200);
temp_offset_hours -= 1;
}
else if (pressed == PB_OK) {
delay(200);
break;
}
else if (pressed == PB_CANCEL) {
delay(200);
return;
}
}
// Step 2: Set UTC Offset (Minutes)
while (true) {
display.clearDisplay();
print_line("UTC Offset (M): " + String(temp_offset_minutes), 0, 0, 2);
int pressed = wait_for_button_press();
if (pressed == PB_UP) {
delay(200);
temp_offset_minutes = (temp_offset_minutes == 30) ? 0 : 30; // Toggle between 0 and 30
}
else if (pressed == PB_DOWN) {
delay(200);
temp_offset_minutes = (temp_offset_minutes == 30) ? 0 : 30; // Toggle between 0 and 30
}
else if (pressed == PB_OK) {
delay(200);
user_utc_offset = (temp_offset_hours * 3600) + (temp_offset_minutes * 60); // Convert to seconds
configTime(user_utc_offset, UTC_OFFSET_DST, NTP_SERVER);
break;
}
else if (pressed == PB_CANCEL) {
delay(200);
return;
}
}
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_minute = minutes;
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) {
delay(200);
temp_minute -= 1;
if (temp_minute < 0) {
temp_minute = 59;
}
}
else if (pressed == PB_OK) {
delay(200);
minutes = temp_minute;
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_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) {
delay(200);
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);
n_alarms = n_alarms + 1;
delay(1000);
}
void view_active_alarms() {
display.clearDisplay();
if (n_alarms == 0) {
print_line("No Alarms Set", 0, 0, 2);
while (digitalRead(PB_CANCEL) == HIGH) {
delay(100); // Wait for cancel button press
}
return;
}
while (digitalRead(PB_CANCEL) == HIGH) {
display.clearDisplay();
String alarmText1 = "Alarm 1: " + String(alarm_hours[0]) + ":" + (alarm_minutes[0] < 10 ? "0" : "") + String(alarm_minutes[0]);
String alarmText2 = "Alarm 2: " + String(alarm_hours[1]) + ":" + (alarm_minutes[1] < 10 ? "0" : "") + String(alarm_minutes[1]);
print_line(alarmText1, 0, 0, 2);
print_line(alarmText2, 0, 30, 2); // Display second alarm below the first
display.display();
}
}
void delete_alarm() {
display.clearDisplay();
if (n_alarms == 0) {
print_line("No Alarms Set", 0, 0, 2);
while (digitalRead(PB_CANCEL) == HIGH) {
delay(100); // Wait for cancel button press
}
return;
}
// Loop through alarms for deletion
for (int i = 0; i < n_alarms; i++) {
if (alarm_hours[i] >= 0 && alarm_hours[i] < 24 && alarm_minutes[i] >= 0 && alarm_minutes[i] < 60) {
while (true) {
display.clearDisplay();
String alarmText = "Alarm " + String(i + 1) + ": " +
String(alarm_hours[i]) + ":" +
(alarm_minutes[i] < 10 ? "0" : "") + String(alarm_minutes[i]);
print_line(alarmText, 0, 0, 2);
print_line("Delete?", 0, 30, 2);
display.display();
int pressed = wait_for_button_press();
if (pressed == PB_OK) {
delay(200);
alarm_hours[i] = -1; // Mark alarm as deleted
alarm_minutes[i] = -1;
alarm_triggered[i] = false;
display.clearDisplay();
print_line("Alarm " + String(i + 1) + " Deleted!", 0, 0, 2);
n_alarms = n_alarms - 1;
display.display();
delay(1500); // Show confirmation message
break; // Move to next alarm or exit
}
else if (pressed == PB_CANCEL) {
delay(200);
break; // Skip this alarm and move to the next one
}
}
}
}
}
void run_mode(int mode) {
if (mode == 0) {
set_time();
}
else if (mode == 1 || mode == 2) {
set_alarm(mode - 1);
}
else if (mode == 3) {
view_active_alarms();
}
else if (mode == 4) {
delete_alarm();
}
}
void check_temp() {
TempAndHumidity data = dhtSensor.getTempAndHumidity();
display.clearDisplay();
String tempText = "Temp: " + String(data.temperature) + "C";
String humidityText = "Humidity: " + String(data.humidity) + "%";
print_line(tempText, 0, 0, 1);
print_line(humidityText, 0, 20, 1);
bool warning = false;
// Check Temperature Warning
if (data.temperature < 24) {
print_line("WARNING: TEMP LOW!", 0, 40, 1);
warning = true;
}
else if (data.temperature > 32) {
print_line("WARNING: TEMP HIGH!", 0, 40, 1);
warning = true;
}
// Check Humidity Warning
if (data.humidity < 65) {
print_line("WARNING: HUMIDITY LOW!", 0, 50, 1);
warning = true;
}
else if (data.humidity > 80) {
print_line("WARNING: HUMIDITY HIGH!", 0, 50, 1);
warning = true;
}
// If a warning is triggered, turn on LED or buzzer
if (warning) {
digitalWrite(LED_1, HIGH);
tone(BUZZER, 1000); // Beep at 1kHz for warning
delay(100);
noTone(BUZZER);
} else {
digitalWrite(LED_1, LOW);
}
display.display();
delay(1000); // Refresh every 2 seconds
}
esp1:0
esp1:2
esp1:4
esp1:5
esp1:12
esp1:13
esp1:14
esp1:15
esp1:16
esp1:17
esp1:18
esp1:19
esp1:21
esp1:22
esp1:23
esp1:25
esp1:26
esp1:27
esp1:32
esp1:33
esp1:34
esp1:35
esp1:3V3
esp1:EN
esp1:VP
esp1:VN
esp1:GND.1
esp1:D2
esp1:D3
esp1:CMD
esp1:5V
esp1:GND.2
esp1:TX
esp1:RX
esp1:GND.3
esp1:D1
esp1:D0
esp1:CLK
oled1:GND
oled1:VCC
oled1:SCL
oled1:SDA
r1:1
r1:2
bz1:1
bz1:2
led1:A
led1:C
r2:1
r2:2
btn1:1.l
btn1:2.l
btn1:1.r
btn1:2.r
r3:1
r3:2
btn2:1.l
btn2:2.l
btn2:1.r
btn2:2.r
r4:1
r4:2
btn3:1.l
btn3:2.l
btn3:1.r
btn3:2.r
r5:1
r5:2
btn4:1.l
btn4:2.l
btn4:1.r
btn4:2.r
r6:1
r6:2
dht1:VCC
dht1:SDA
dht1:NC
dht1:GND