char ssid[] = "Wokwi-GUEST";
char pass[] = "";
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DFRobotDFPlayerMini.h>
#include <WiFi.h>
#include <WiFiClient.h>
#define rled 26
#define bled 25
#define NTP_SERVER "pool.ntp.org"
#define UTC_OFFSET 3*3600
#define UTC_OFFSET_DST 0
#define buzzer 15
// ====== Period Structure ======
struct Period {
int startHour;
int startMinute;
int endHour;
int endMinute;
const char* subject;
int periodNumber;
};
// ====== Sample Daily Timetable ======
Period timetable[] = {
{8, 0, 8, 45, "Mathematics", 1},
{8, 50, 9, 35, "English", 2},
{9, 40, 10,25, "Science", 3},
{10,30,11,15, "Geography", 4},
{19,20,20,15, "Kiswahili", 5},
{20,20,21,15, "Civics", 6}
};
const int totalPeriods = sizeof(timetable) / sizeof(timetable[0]);
String currentSub,nextSub;
int periodNum,oldNum;
bool changed;
LiquidCrystal_I2C lcd(0x27, 20, 4);
LiquidCrystal_I2C lcd1(0x28, 20, 4);
void setup()
{
Serial.begin(9600);
delay(500);
Serial.println("initializing");
pinMode(buzzer, OUTPUT);
pinMode(bled, OUTPUT);
pinMode(rled, OUTPUT);
digitalWrite(rled,HIGH);
digitalWrite(bled,LOW);
lcd.init();
lcd1.init();
lcd.backlight();
lcd1.backlight();
loadingdisplay();
clearLine(3);
clearLine(3);
lcd.setCursor(0, 3);
lcd.print("Connecting WiFi....");
WiFi.begin("Wokwi-GUEST", "", 6);
while (WiFi.status() != WL_CONNECTED) {
delay(250);
spinner();
}
Serial.println("");
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
clearLine(3);
lcd.setCursor(0, 3);
lcd.print("WiFi connected");
delay(2000);
clearLine(3);
lcd.setCursor(0, 3);
lcd.print("Updating time...");
configTime(UTC_OFFSET, UTC_OFFSET_DST, NTP_SERVER);
clearLine(3);
lcd.setCursor(0, 3);
lcd.print("Time Updated");
delay(2000);
clearLine(3);
lcd.setCursor(0, 3);
lcd.print("Initialize voice...");
Serial2.begin(9600);
clearLine(3);
lcd.setCursor(0, 3);
lcd.print("Voice Initialized");
delay(2000);
lcd.clear();
digitalWrite(rled,HIGH);
digitalWrite(bled,HIGH);
}
void loop()
{
check();
homedisplay();
}
void check()
{
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
return;
}
// Extract hours and minutes
int currentHour = timeinfo.tm_hour;
int currentMinute = timeinfo.tm_min;
bool found = false;
for (int i = 0; i < totalPeriods; i++) {
if (isWithinPeriod(currentHour, currentMinute, timetable[i]))
{
periodNum=timetable[i].periodNumber;
currentSub=String(timetable[i].subject);
if (i + 1 < totalPeriods) {
nextSub=String(timetable[i+1].subject);
} else {
nextSub="NONE(END)";
}
found = true;
digitalWrite(bled,HIGH);
if(oldNum!=periodNum)
{
changed=true;
oldNum=periodNum;
Alert(periodNum);
}
break;
}
}
if (!found) {
digitalWrite(bled,LOW);
}
}
bool isWithinPeriod(int hour, int minute, Period p)
{
int now = hour * 60 + minute;
int start = p.startHour * 60 + p.startMinute;
int end = p.endHour * 60 + p.endMinute;
return now >= start && now <= end;
}
void loadingdisplay()
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print("=>SMART TIMETABLE <=");
lcd.setCursor(0,1);
lcd.print(" FOR SCHOOL ");
lcd.setCursor(0,2);
lcd.print(" SYSTEM INITIALIZE ");
lcd.setCursor(0,3);
lcd.print("PLEASE WAIT");
for(int k=11;k<20;k++)
{
lcd.setCursor(k,3);
lcd.print(".");
delay(200);
}
}
void homedisplay()
{
struct tm timeinfo;
if (!getLocalTime(&timeinfo))
{
lcd.setCursor(0, 3);
lcd.print("Connection Err");
return;
}
if(changed)
{
changed=false;
lcd.clear();
lcd1.clear();
}
//===========================================
lcd.setCursor(0,0);
lcd.print("*SCHOOL TIME TABLE*");
lcd.setCursor(0,1);
lcd.print("PERIOD NUMBER:");
lcd.setCursor(15,1);
lcd.print(periodNum);
lcd.setCursor(0,2);
lcd.print(&timeinfo, "%H:%M:%S %d/%m/%Y");
lcd.setCursor(0,3);
lcd.print("=========<>=========");
//==========================================
lcd1.setCursor(0,0);
lcd1.print("*SUBJECT SCHEDULE*");
lcd1.setCursor(0,1);
lcd1.print("NOW :");
lcd1.setCursor(5,1);
lcd1.print(currentSub);
lcd1.setCursor(0,2);
lcd1.print("NEXT:");
lcd1.setCursor(5,2);
lcd1.print(nextSub);
lcd.setCursor(0,3);
lcd.print("=========<>=========");
}
void Alert(uint8_t num)
{
for(uint8_t q=0;q<num;q++){
digitalWrite(buzzer, HIGH);
digitalWrite(rled, HIGH);
tone(buzzer, 100);
delay(1000);
digitalWrite(buzzer, LOW);
digitalWrite(rled, LOW);
noTone(buzzer);
delay(1000);}
}
void clearLine(uint8_t lineNum)
{
for(uint8_t i=0;i<20;i++)
{
lcd.setCursor(i,lineNum);
lcd.print(" ");
}
}
void printLocalTime() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
lcd.setCursor(0, 3);
lcd.print("Connection Err");
return;
}
lcd.setCursor(0,3);
lcd.print(&timeinfo, "%H:%M:%S %d/%m/%Y");
}
void spinner()
{
static int8_t counter = 0;
const char* glyphs = "\xa1\xa5\xdb";
lcd.setCursor(19, 3);
lcd.print(glyphs[counter++]);
if (counter == strlen(glyphs)) {
counter = 0;
}
}