//include libraries
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DHTesp.h>
//define the parameters of OLED
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#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
//Declare objects
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire,OLED_RESET);
DHTesp dhtSensor;
//global variables
//initially all the time parameters are 0
int days = 0;
int hours=0;
int minutes=0;
int seconds=0;
unsigned long timeNow = 0; //as time is a big value to represent we use long format and also time is always positive, so we used unsigned for it.
unsigned long timeLast= 0; //this is essential to calculate current time
bool alarm_enabled=true;
int n_alarms=2; //to keep track on number of alarms
int alarm_hours[]={0,1}; //initial alaram hours
int alarm_minutes[]={1,10};//initial alarm minutes (1st minute and 10th minute)
bool alarm_triggered[] = {false,false}; //to check whether alarm has been triggered and user responded
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 = 4;
String modes[]= {"1- Set time", "2 - Set alarm", "3 - Set alarm 2", "4 - Disable alarms"};
void setup() {
// put your setup code here, to run once:
pinMode(BUZZER,OUTPUT);
pinMode(LED_1,OUTPUT);
pinMode(PB_CANCEL, INPUT);
pinMode(PB_UP, INPUT);
pinMode(PB_OK, INPUT);
pinMode(PB_DOWN, INPUT);
Serial.begin(115200);
dhtSensor.setup(DHTPIN, DHTesp::DHT22);
// SSD1306_SWITCHCAPVCC - generate dispaly voltage from 3.3 V internally
//implement if clause to check whether the display is initially working properly
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)){
Serial.println(F("SSD1306 allocation failed"));
for(;;); //implement an infinite loop
}
//show the display buffer on the screen. You MUST call display() after
//drawing commands to make them visible on screen!
display.display();
delay(2000);
//clear the buffer
display.clearDisplay();
print_line("Welcome to Medibox", 10,20,2);
delay(2000);
display.clearDisplay();
}
void loop() {
// put your main code here, to run repeatedly:
update_time_with_set_alarms();
if(digitalRead(PB_OK)==LOW){ //direct the user to menu if he pressed OK
delay(200);//to debounce the push button
go_to_menu();
}
check_temp();
}
//This function prints the text we want in the display in the required place mentioned(column,row)
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(void){
//here 10 pixels for 1 character. So integer values of days take 2 characters at maximum. So, 20 pixels are enough.
display.clearDisplay();//this prevents time is printing over itself
print_line(String(days),0,0,2);
print_line(":",20,0,2);
print_line(String(hours),30,0,2);
print_line(":",40,0,2);
print_line(String(minutes),60,0,2);
print_line(":",60,0,2);
print_line(String(seconds),90,0,2);
}
void update_time(){
timeNow= millis()/1000; //represent seconds passes after bootup
seconds= timeNow-timeLast;
if(seconds>=60){
minutes+=1;
timeLast+=60; // always seconds never go beyond 60
}
if (minutes ==60){
hours+=1;
minutes=0;
}
if(hours==24){
days+=1;
hours=0;
}
}
void ring_alarm(){
display.clearDisplay();
print_line("Medicine Time",0,0,2);
digitalWrite(LED_1,HIGH);
bool break_happened = false;//this is to handle situations like user does not push the button very fast.
//ring the buzzer
while( break_happened == false && digitalRead(PB_CANCEL)==HIGH){
for(int i=0;i<n_notes;i++){
if(digitalRead(PB_CANCEL) == LOW){
delay(200); // prevent bouncing the push button
break_happened = true; // this true if the button is pressed only do not want to release it
break;
}
tone(BUZZER,notes[i]);
delay(500);
noTone(BUZZER);
delay(2);
}
}
digitalWrite(LED_1,LOW);
display.clearDisplay();
}
void update_time_with_set_alarms(void){
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 is to stop the alarm after user pressed the button. without this if the user press the alarm at the same minute the alarm beeps, alarm will again start to beep.
}
}
}
}
int wait_for_button_press(){
while(true){ //infinite loop until the button press
if(digitalRead(PB_UP)==LOW){
delay(200);
return PB_UP; // this return the value of the input as well as going out of the infinite loop
}
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(digitalRead(PB_CANCEL)== HIGH){
//this while loop will execute until the user press cancel button
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_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);
hours= 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);
}
void run_mode(int mode){
if (mode==0){
set_time();
}
if (mode ==1 || mode == 2){
set_alarm(mode-1);
}
else if(mode== 3){
alarm_enabled = false;
}
}
void check_temp(){
TempAndHumidity data = dhtSensor.getTempAndHumidity();//those functions can be found in documentation of library
//this data type is not a common arduino data type. This is belong to DHT22 library
if (data.temperature > 35){
display.clearDisplay();
print_line("Temp. High",0,40,1);
}
else 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);//changed the row to 50 so that the temp. and humidity mesaages do not overlap
}
else if (data.temperature < 20){
display.clearDisplay();
print_line("Humidity LOW",0,50,1);
}
}