#include <Wire.h>
#include <RTClib.h>
#include <LiquidCrystal_I2C.h>
#include <math.h>
RTC_DS1307 rtc;
LiquidCrystal_I2C lcd(0x27, 16, 2); // Pas het I2C-adres aan indien nodig
double latitude = 51.499998; // Bergen op Zoom
double longitude = 4.2999988; // Bergen op Zoom
double timezone = -2.0; // Bergen op Zoom (CET, UTC+1 in winter, +2 in summer)
double julian_date;
enum CalculationMethod { Custom, CalculationMethodsCount };
enum JuristicMethod { Shafii, Hanafi };
enum AdjustingMethod { None, MidNight, OneSeventh, AngleBased };
enum { Fajr, Sunrise, Dhuhr, Asr, Sunset, Maghrib, Isha, TimesCount };
struct MethodConfig {
double fajr_angle;
double maghrib_value;
bool maghrib_is_minutes;
double isha_value;
bool isha_is_minutes;
};
struct DoublePair {
double first;
double second;
};
MethodConfig method_params[CalculationMethodsCount];
CalculationMethod calc_method = Custom;
JuristicMethod asr_juristic = Shafii;
AdjustingMethod adjust_high_lats = None;
double dhuhr_minutes = 0; // minutes after mid-day for Dhuhr
void setup() {
rtc.begin();
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// Hardcode the time to a specific value
//rtc.adjust(DateTime(2024, 5, 29, 13, 39, 40)); // Set the time to 21:47:50 on 29 May 2024
lcd.init();
lcd.backlight();
// Initialize prayer calculation method parameters
method_params[Custom] = { 18.0, 4.0, true, 17.0, false }; // Set Isha angle to 17 degrees
}
void loop() {
DateTime now = rtc.now();
// Check for Daylight Saving Time
bool isDST = isDaylightSavingTime(now);
timezone = isDST ? 2.0 : 1.0; // Adjust timezone for DST
double times[TimesCount];
get_prayer_times(now.year(), now.month(), now.day(), latitude, longitude, timezone, times);
// Display current date and time
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Datum:");
lcd.print(two_digits_format(now.day()));
lcd.print("-");
lcd.print(two_digits_format(now.month()));
lcd.print("-");
lcd.print(now.year());
lcd.setCursor(0, 1);
lcd.print("Tijd: ");
lcd.print(two_digits_format(now.hour()));
lcd.print(":");
lcd.print(two_digits_format(now.minute()));
lcd.print(":");
lcd.print(two_digits_format(now.second()));
delay(2000);
// Display prayer times in the specified format
displayPrayerTimes(times);
}
void displayPrayerTimes(double times[]) {
const char* timeNames[] = {"Fajr", "Sunrise", "Dhuhr", "Asr", "Sunset", "Maghrib", "Isha"};
int hours, minutes;
// Display Fajr and Sunrise
lcd.clear();
lcd.setCursor(0, 0);
get_float_time_parts(times[Fajr], hours, minutes);
lcd.print("Fajr: ");
lcd.print(two_digits_format(hours) + ":" + two_digits_format(minutes));
lcd.setCursor(0, 1);
get_float_time_parts(times[Sunrise], hours, minutes);
lcd.print("Sunrise: ");
lcd.print(two_digits_format(hours) + ":" + two_digits_format(minutes));
delay(1000);
// Display Dhuhr and Asr
lcd.clear();
lcd.setCursor(0, 0);
get_float_time_parts(times[Dhuhr], hours, minutes);
lcd.print("Dhuhr: ");
lcd.print(two_digits_format(hours) + ":" + two_digits_format(minutes));
lcd.setCursor(0, 1);
get_float_time_parts(times[Asr], hours, minutes);
lcd.print("Asr: ");
lcd.print(two_digits_format(hours) + ":" + two_digits_format(minutes));
delay(1000);
// Display Sunset and Maghrib
lcd.clear();
lcd.setCursor(0, 0);
get_float_time_parts(times[Sunset], hours, minutes);
lcd.print("Sunset: ");
lcd.print(two_digits_format(hours) + ":" + two_digits_format(minutes));
lcd.setCursor(0, 1);
get_float_time_parts(times[Maghrib], hours, minutes);
lcd.print("Maghrib: ");
lcd.print(two_digits_format(hours) + ":" + two_digits_format(minutes));
delay(1000);
// Display Isha
lcd.clear();
lcd.setCursor(0, 0);
get_float_time_parts(times[Isha], hours, minutes);
lcd.print("Isha: ");
lcd.print(two_digits_format(hours) + ":" + two_digits_format(minutes));
delay(1000);
}
// Check if a given date is within Daylight Saving Time period
bool isDaylightSavingTime(DateTime dt) {
// DST starts last Sunday of March
DateTime startDST(dt.year(), 3, lastSunday(3, dt.year()), 2, 0, 0);
// DST ends last Sunday of October
DateTime endDST(dt.year(), 10, lastSunday(10, dt.year()), 3, 0, 0);
return dt >= startDST && dt < endDST;
}
// Calculate the last Sunday of a given month
int lastSunday(int month, int year) {
DateTime dt(year, month + 1, 1);
int dayOfWeek = dt.dayOfTheWeek(); // 0 = Sunday, 1 = Monday, ..., 6 = Saturday
return 31 - ((dayOfWeek + 1) % 7);
}
// Prayer time calculation functions
double dsin(double d) { return sin(deg2rad(d)); }
double dcos(double d) { return cos(deg2rad(d)); }
double dtan(double d) { return tan(deg2rad(d)); }
double darcsin(double x) { return rad2deg(asin(x)); }
double darccos(double x) { return rad2deg(acos(x)); }
double darctan(double x) { return rad2deg(atan(x)); }
double darctan2(double y, double x) { return rad2deg(atan2(y, x)); }
double darccot(double x) { return rad2deg(atan(1.0 / x)); }
double deg2rad(double d) { return d * M_PI / 180.0; }
double rad2deg(double r) { return r * 180.0 / M_PI; }
double fix_angle(double a) { a = a - 360.0 * floor(a / 360.0); return a < 0.0 ? a + 360.0 : a; }
double fix_hour(double a) { a = a - 24.0 * floor(a / 24.0); return a < 0.0 ? a + 24.0 : a; }
double get_julian_date(int year, int month, int day) {
if (month <= 2) {
year -= 1;
month += 12;
}
double a = floor(year / 100.0);
double b = 2 - a + floor(a / 4.0);
return floor(365.25 * (year + 4716)) + floor(30.6001 * (month + 1)) + day + b - 1524.5;
}
void compute_day_times(double times[]) {
double default_times[] = { 5, 6, 12, 13, 18, 18, 18 };
for (int i = 0; i < TimesCount; ++i) times[i] = default_times[i];
for (int i = 0; i < 1; ++i) compute_times(times);
adjust_times(times);
}
DoublePair sun_position(double jd) {
double d = jd - 2451545.0;
double g = fix_angle(357.529 + 0.98560028 * d);
double q = fix_angle(280.459 + 0.98564736 * d);
double l = fix_angle(q + 1.915 * dsin(g) + 0.020 * dsin(2 * g));
double e = 23.439 - 0.00000036 * d;
double dd = darcsin(dsin(e) * dsin(l));
double ra = darctan2(dcos(e) * dsin(l), dcos(l)) / 15.0;
ra = fix_hour(ra);
double eq_t = q / 15.0 - ra;
DoublePair dp = {dd, eq_t};
return dp;
}
void set_asr_method(JuristicMethod method_id) {
asr_juristic = method_id;
}
void set_high_lats_adjust_method(AdjustingMethod method_id) {
adjust_high_lats = method_id;
}
double sun_declination(double jd) {
return sun_position(jd).first;
}
double equation_of_time(double jd) {
return sun_position(jd).second;
}
double compute_mid_day(double _t) {
double t = equation_of_time(julian_date + _t);
double z = fix_hour(12 - t);
return z;
}
double compute_time(double g, double t) {
double d = sun_declination(julian_date + t);
double z = compute_mid_day(t);
double v = 1.0 / 15.0 * darccos((-dsin(g) - dsin(d) * dsin(latitude)) / (dcos(d) * dcos(latitude)));
return z + (g > 90.0 ? -v : v);
}
double compute_asr(int step, double t) {
double d = sun_declination(julian_date + t);
double g = -darccot(step + dtan(fabs(latitude - d)));
return compute_time(g, t);
}
void compute_times(double times[]) {
day_portion(times);
times[Fajr] = compute_time(180.0 - method_params[calc_method].fajr_angle, times[Fajr]);
times[Sunrise] = compute_time(180.0 - 0.833, times[Sunrise]);
times[Dhuhr] = compute_mid_day(times[Dhuhr]);
times[Asr] = compute_asr(1 + asr_juristic, times[Asr]);
times[Sunset] = compute_time(0.833, times[Sunset]);
times[Maghrib] = compute_time(method_params[calc_method].maghrib_value, times[Maghrib]);
times[Isha] = compute_time(method_params[calc_method].isha_value, times[Isha]);
}
double time_diff(double time1, double time2) {
return fix_hour(time2 - time1);
}
String int_to_string(int num) {
return String(num);
}
String two_digits_format(int num) {
char tmp[16];
tmp[0] = '\0';
sprintf(tmp, "%2.2d", num);
return String(tmp);
}
double night_portion(double angle) {
switch (adjust_high_lats) {
case AngleBased:
return angle / 60.0;
case MidNight:
return 1.0 / 2.0;
case OneSeventh:
return 1.0 / 7.0;
default:
return 0;
}
}
void adjust_high_lat_times(double times[]) {
double night_time = time_diff(times[Sunset], times[Sunrise]);
double fajr_diff = night_portion(method_params[calc_method].fajr_angle) * night_time;
if (isnan(times[Fajr]) || time_diff(times[Fajr], times[Sunrise]) > fajr_diff)
times[Fajr] = times[Sunrise] - fajr_diff;
double isha_angle = method_params[calc_method].isha_is_minutes ? 18.0 : method_params[calc_method].isha_value;
double isha_diff = night_portion(isha_angle) * night_time;
if (isnan(times[Isha]) || time_diff(times[Sunset], times[Isha]) > isha_diff)
times[Isha] = times[Sunset] + isha_diff;
double maghrib_angle = method_params[calc_method].maghrib_is_minutes ? 4.0 : method_params[calc_method].maghrib_value;
double maghrib_diff = night_portion(maghrib_angle) * night_time;
if (isnan(times[Maghrib]) || time_diff(times[Sunset], times[Maghrib]) > maghrib_diff)
times[Maghrib] = times[Sunset] + maghrib_diff;
}
void adjust_times(double times[]) {
for (int i = 0; i < TimesCount; ++i)
times[i] += timezone - longitude / 15.0;
times[Dhuhr] += dhuhr_minutes / 60.0;
if (method_params[calc_method].maghrib_is_minutes)
times[Maghrib] = times[Sunset] + method_params[calc_method].maghrib_value / 60.0;
if (method_params[calc_method].isha_is_minutes)
times[Isha] = times[Maghrib] + method_params[calc_method].isha_value / 60.0;
if (adjust_high_lats != None)
adjust_high_lat_times(times);
}
void day_portion(double times[]) {
for (int i = 0; i < TimesCount; ++i)
times[i] /= 24.0;
}
void get_prayer_times(int year, int month, int day, double _latitude, double _longitude, double _timezone, double times[]) {
latitude = _latitude;
longitude = _longitude;
timezone = _timezone;
julian_date = get_julian_date(year, month, day) - longitude / (double)(15 * 24);
compute_day_times(times);
// Check vaste tijden voor fajr en Isha.
//Fajr is op 03:30 uur van 5 mei tot en met 4 augustus // Set Fajr to 03:30 between 5-5 and 4-8
//Isha is op 23:30 uur van 3 mei tot en met 10 augustus // Set Isha to 23:30 between 3-5 and 10-8
if ((month == 5 && day >= 5) || (month == 6) || (month == 8 && day <= 4)) {
times[Fajr] = 3.5; // 03:30 in decimal hours
}
if ((month == 5 && day >= 3) || (month == 6) || (month == 7) || (month == 8 && day <= 10)) {
times[Isha] = 23.5; // 23:30 in decimal hours
}
}
void set_calc_method(CalculationMethod method_id) {
calc_method = method_id;
}
void set_fajr_angle(double angle) {
method_params[Custom].fajr_angle = angle;
calc_method = Custom;
}
void set_maghrib_angle(double angle) {
method_params[Custom].maghrib_is_minutes = false;
method_params[Custom].maghrib_value = angle;
calc_method = Custom;
}
void set_isha_angle(double angle) {
method_params[Custom].isha_is_minutes = false;
method_params[Custom].isha_value = angle;
calc_method = Custom;
}
void set_dhuhr_minutes(double minutes) {
dhuhr_minutes = minutes;
}
void set_maghrib_minutes(double minutes) {
method_params[Custom].maghrib_is_minutes = true;
method_params[Custom].maghrib_value = minutes;
calc_method = Custom;
}
void set_isha_minutes(double minutes) {
method_params[Custom].isha_is_minutes = true;
method_params[Custom].isha_value = minutes;
calc_method = Custom;
}
void get_float_time_parts(double time, int& hours, int& minutes) {
time = fix_hour(time + 0.5 / 60); // add 0.5 minutes to round
hours = floor(time);
minutes = floor((time - hours) * 60);
}