#include <WiFi.h>
#include <time.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DHTesp.h>
#define WFI_SSID "Wokwi-GUEST"
#define WFI_PASS ""
#define LED_1SEC 26
#define BTN_MENU 33
#define BTN_PLUS 32
#define BTN_MNUS 35
#define BTN_CNCL 34
#define DHT_DATA 25
// OLED Display COnfiguration
#define DSP_WDTH 128
#define DSP_HIGT 64
#define DSP_RSET -1
#define DSP_ADDR 0x3C
// NTP Configuration
#define NTP_SRVR "pool.ntp.org"
enum Button_state {
off,
potential_press,
press,
hold
};
hw_timer_t *TIM_1SEC = NULL;
Adafruit_SSD1306 DSP_object(DSP_WDTH, DSP_HIGT, &Wire, DSP_RSET);
DHTesp DHT_object;
String date_formatted_string;
String time_formatted_string;
int utc_offset = 0;
int p_utc_offset = 0;
unsigned int alarm_times[3];
unsigned int p_alarm_times[3];
time_t current_time;
int hours = 0;
int minutes = 0;
int seconds = 0;
int day = 0;
int month = 0;
int year = 0;
Button_state BTN_MENU_state;
Button_state BTN_PLUS_state;
Button_state BTN_MNUS_state;
Button_state BTN_CNCL_state;
unsigned int BTN_MENU_counter;
unsigned int BTN_PLUS_counter;
unsigned int BTN_MNUS_counter;
unsigned int BTN_CNCL_counter;
TempAndHumidity DHT_data;
int menu = 0;
int edit = false;
bool editing_mins = false;
void connectToWifi() {
WiFi.begin(WFI_SSID, WFI_PASS);
int retries = 0;
while (WiFi.status() != WL_CONNECTED) {
retries++;
delay(1000);
if(retries == 3) {
show_splaash_screen("Check Wi-Fi AP");
}
}
}
void disconnectFromWifi() {
WiFi.disconnect();
}
void getTime() {
configTime(utc_offset, 0, NTP_SRVR);
struct tm timeinfo;
int retries = 0;
while(!getLocalTime(&timeinfo)) {
retries++;
delay(1000);
if(retries == 3) {
show_splaash_screen("No Internet Connection");
}
}
current_time = mktime(&timeinfo);
}
void IRAM_ATTR TIM_1SEC_ISR() {
digitalWrite(LED_1SEC, !digitalRead(LED_1SEC));
current_time++;
}
void IRAM_ATTR BTN_ISR() {
menu++;
detachInterrupt(digitalPinToInterrupt(BTN_MENU));
}
void DSP_print_text(String text, int col, int row, int size) {
DSP_object.setTextSize(size);
DSP_object.setTextColor(WHITE);
DSP_object.setCursor(col, row);
DSP_object.println(text);
}
void show_splaash_screen(String status) {
DSP_object.clearDisplay();
DSP_print_text("SMART" , 10, 5, 2);
DSP_print_text("Medi Box", 10, 25, 2);
DSP_print_text(status , 10, 50, 1);
DSP_object.display();
}
void show_home_screen() {
DSP_object.clearDisplay();
char tempAndHumString[18];
snprintf(tempAndHumString, sizeof(tempAndHumString), "%04.1f^C %04.1f%%", DHT_data.temperature, DHT_data.humidity);
DSP_print_text(date_formatted_string, 10, 4, 1);
DSP_print_text(time_formatted_string, 10, 18, 2);
DSP_print_text("Next Alarm: 13:30" , 10, 43, 1);
DSP_print_text(tempAndHumString , 10, 55, 1);
DSP_object.display();
}
void show_menu_timezone() {
DSP_object.clearDisplay();
char timeZoneString[6];
char sn = utc_offset > 0 ? '+' : (utc_offset < 0 ? '-' : ' ' );
int hr = (utc_offset / 2) * (utc_offset < 0 ? -1 : 1);
int mn = utc_offset % 2;
snprintf(timeZoneString, sizeof(timeZoneString), "%c%02d%02d",sn, hr, mn);
DSP_print_text("Set time zone" , 10, 4, 1);
DSP_print_text(timeZoneString , 10, 18, 2);
DSP_print_text(time_formatted_string , 10, 43, 1);
DSP_print_text(date_formatted_string , 10, 55, 1);
DSP_object.display();
}
void show_menu_alarm(int alarm) {
DSP_object.clearDisplay();
char alarmTimeString[6];
char sn = utc_offset > 0 ? '+' : (utc_offset < 0 ? '-' : ' ' );
int hr = (utc_offset / 2) * (utc_offset < 0 ? -1 : 1);
int mn = utc_offset % 2;
snprintf(alarmTimeString, sizeof(alarmTimeString), "%c%02d%02d",sn, hr, mn);
DSP_print_text("Set alarm zone" , 10, 4, 1);
DSP_print_text(alarmTimeString , 10, 18, 2);
DSP_print_text(time_formatted_string , 10, 43, 1);
DSP_print_text(date_formatted_string , 10, 55, 1);
DSP_object.display();
}
void hardCodeTime() {
configTime(utc_offset, 0, NTP_SRVR);
current_time = 1710073584l;
}
void setTimeString() {
struct tm *timeinfo = localtime(¤t_time);
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 timeDate[11];
strftime(timeDate, 11, "%F", timeinfo);
date_formatted_string = timeDate;
char timeTime[25];
strftime(timeTime, 25, "%H:%M:%S", timeinfo);
time_formatted_string = timeTime;
}
void getTempetarureandHumidity() {
DHT_data = DHT_object.getTempAndHumidity();
}
void setup() {
Serial.begin(115200);
pinMode(LED_1SEC, OUTPUT);
pinMode(BTN_MENU, INPUT);
pinMode(BTN_PLUS, INPUT);
pinMode(BTN_MNUS, INPUT);
pinMode(BTN_CNCL, INPUT);
BTN_MENU_state = off;
BTN_PLUS_state = off;
BTN_MNUS_state = off;
BTN_CNCL_state = off;
while(!DSP_object.begin(SSD1306_SWITCHCAPVCC, DSP_ADDR)) {
delay(3000);
}
DHT_object.setup(DHT_DATA, DHTesp::DHT22);
// show_splaash_screen("by Tharindu Perera");
// delay(300);
// connectToWifi();
// show_splaash_screen("by Tharindu Perera");
// delay(300);
// getTime();
// show_splaash_screen("by Tharindu Perera");
// delay(300);
// disconnectFromWifi();
// show_splaash_screen("Initialized");
// delay(300);
hardCodeTime();
attachInterrupt(BTN_MENU, BTN_ISR, FALLING);
TIM_1SEC = timerBegin(0, 80, true);
timerAttachInterrupt(TIM_1SEC, &TIM_1SEC_ISR, true);
timerAlarmWrite(TIM_1SEC, 1000 * 1000, true);
timerAlarmEnable(TIM_1SEC);
getTempetarureandHumidity();
show_home_screen();
}
void updateButtonStates() {
updateButtonState(BTN_MENU, &BTN_MENU_state, &BTN_MENU_counter);
updateButtonState(BTN_PLUS, &BTN_PLUS_state, &BTN_PLUS_counter);
updateButtonState(BTN_MNUS, &BTN_MNUS_state, &BTN_MNUS_counter);
updateButtonState(BTN_CNCL, &BTN_CNCL_state, &BTN_CNCL_counter);
}
void updateButtonState(int btn, Button_state *state, unsigned int *counter) {
if(digitalRead(btn)) {
if(*counter > 10) *state = hold;
else if (*counter > 1) *state = potential_press;
*counter++;
}
else {
if (*state == potential_press) *state = press;
else *state == off;
*counter = 0;
}
}
int navigate () {
if (BTN_PLUS_state == press) return menu++;
if (BTN_MNUS_state == press) return menu++;
if (BTN_CNCL_state == press) return menu = 0;
if (BTN_MENU_state == press) return edit++;
}
int edit_values() {
if(menu == 1) {
if (BTN_PLUS_state == press || BTN_PLUS_state == hold) return utc_offset++;
if (BTN_MNUS_state == press || BTN_MNUS_state == hold) return utc_offset--;
if (BTN_CNCL_state == press || BTN_MENU_state == press) edit--;
if (BTN_CNCL_state == press) return utc_offset = p_utc_offset;
if (BTN_MENU_state == press) return p_utc_offset = utc_offset;
return 0;
}
int alarm = menu - 2;
if (BTN_PLUS_state == press || BTN_PLUS_state == hold) return alarm_times[alarm] += (60 - editing_mins * 59);
if (BTN_MNUS_state == press || BTN_MNUS_state == hold) return alarm_times[alarm] -= (60 - editing_mins * 59);
if (BTN_CNCL_state == press || BTN_MENU_state == press) edit--;
if (BTN_CNCL_state == press) {
edit--;
return alarm_times[alarm] = p_alarm_times[alarm];
}
if (BTN_MENU_state == press) {
if(editing_mins) edit--;
else editing_mins = true;
return p_alarm_times[alarm] = alarm_times[alarm];
}
return 0;
}
void loop() {
// while(menu) {
// updateButtonStates();
// edit ? edit_values() : navigate();
// switch (menu) {
// case 1:
// show_menu_timezone();
// break;
// case 2 ... 4:
// show_menu_alarm(menu - 2);
// break;
// default:
// attachInterrupt(BTN_MENU, BTN_ISR, FALLING);
// menu = 0;
// break;
// }
// delay(50);
// }
getTempetarureandHumidity();
setTimeString();
show_home_screen();
delay(200);
}