#include <Wire.h>
#include "RTClib.h"
#include <TM1637Display.h>
// --- Deklarasi modul TM1637 untuk tampilan yang sudah ada ---
TM1637Display sevSeg1(2, 3); // Jam dan menit (waktu RTC)
TM1637Display sevSeg2(4, 5); // Detik
TM1637Display sevSeg3(6, 7); // Tanggal dan bulan (dengan dash sebagai pemisah)
TM1637Display sevSeg4(8, 9); // Tahun
TM1637Display sevSeg5(10, 11); // Waktu sahur (jam+menit)
TM1637Display sevSeg6(12, 13); // Hitungan mundur (jam+menit) ke sahur
TM1637Display sevSeg7(14, 15); // Hitungan mundur detik ke sahur
TM1637Display sevSeg8(16, 17); // Waktu imsyak (jam+menit)
TM1637Display sevSeg9(18, 19); // Hitungan mundur (jam+menit) ke imsyak
TM1637Display sevSeg10(22, 23); // Hitungan mundur detik ke imsyak
TM1637Display sevSeg11(24, 25); // Waktu subuh (jam+menit)
TM1637Display sevSeg12(26, 27); // Hitungan mundur (jam+menit) ke subuh
TM1637Display sevSeg13(28, 29); // Hitungan mundur detik ke subuh
TM1637Display sevSeg14(30, 31); // Waktu syuruq/terbit (jam+menit)
TM1637Display sevSeg15(32, 33); // Hitungan mundur (jam+menit) ke syuruq/terbit
TM1637Display sevSeg16(34, 35); // Hitungan mundur detik ke syuruq/terbit
// --- Deklarasi modul TM1637 untuk waktu baru ---
// Ishraq/Dhuha
TM1637Display sevSeg17(36, 37); // Tampilkan jam+menit waktu ishraq/dhuha
TM1637Display sevSeg18(38, 39); // Hitungan mundur (jam+menit) ke ishraq/dhuha
TM1637Display sevSeg19(40, 41); // Hitungan mundur detik ke ishraq/dhuha
// Dzuhur/Jumat
TM1637Display sevSeg20(42, 43); // Tampilkan jam+menit waktu dzuhur/jumat
TM1637Display sevSeg21(44, 45); // Hitungan mundur (jam+menit) ke dzuhur/jumat
TM1637Display sevSeg22(46, 47); // Hitungan mundur detik ke dzuhur/jumat
// Ashar
TM1637Display sevSeg23(48, 49); // Tampilkan jam+menit waktu ashar
TM1637Display sevSeg24(50, 51); // Hitungan mundur (jam+menit) ke ashar
TM1637Display sevSeg25(52, 53); // Hitungan mundur detik ke ashar
// Maghrib
TM1637Display sevSeg26(A0, A1); // Tampilkan jam+menit waktu maghrib
TM1637Display sevSeg27(A2, A3); // Hitungan mundur (jam+menit) ke maghrib
TM1637Display sevSeg28(A4, A5); // Hitungan mundur detik ke maghrib
// Isya
TM1637Display sevSeg29(A6, A7); // Tampilkan jam+menit waktu isya
TM1637Display sevSeg30(A8, A9); // Hitungan mundur (jam+menit) ke isya
TM1637Display sevSeg31(A10, A11); // Hitungan mundur detik ke isya
// Iqomah (durasi 11 menit)
// SevSeg32: hitungan mundur (jam+menit)
// SevSeg33: hitungan mundur detik
TM1637Display sevSeg32(A12, A13);
TM1637Display sevSeg33(A14, A15);
RTC_DS1307 rtc;
// --- Konstanta waktu untuk jadwal ---
// Waktu sahur, imsyak, subuh, dan syuruq sudah ada...
const int sahurHour = 3;
const int sahurMinute = 20;
const int imsyakHour = 4;
const int imsyakMinute = 27;
const int subuhHour = 4;
const int subuhMinute = 37;
const int syuruqHour = 5;
const int syuruqMinute = 53;
// Tambahan waktu untuk waktu baru (ubah sesuai kebutuhan)
const int ishraqHour = 6; // contoh: 06:23 untuk ishraq/dhuha
const int ishraqMinute = 23;
const int dzuhurHour = 12; // contoh: 12:01 untuk dzuhur/jumat
const int dzuhurMinute = 1;
const int asharHour = 15; // contoh: 15:09 untuk ashar
const int asharMinute = 9;
const int maghribHour = 18; // contoh: 18:04 untuk maghrib
const int maghribMinute= 4;
const int isyaHour = 19; // contoh: 19:11 untuk isya
const int isyaMinute = 11;
// Durasi iqomah dalam detik (11 menit)
const int iqomahDuration = 11 * 60; // 540 detik
void setup() {
Wire.begin();
rtc.begin();
// Jika RTC belum berjalan, set waktu berdasarkan waktu kompilasi
if (!rtc.isrunning()) {
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
// Atur kecerahan tiap modul (0x00 sampai 0x0f)
sevSeg1.setBrightness(0x0f);
sevSeg2.setBrightness(0x0f);
sevSeg3.setBrightness(0x0f);
sevSeg4.setBrightness(0x0f);
sevSeg5.setBrightness(0x0f);
sevSeg6.setBrightness(0x0f);
sevSeg7.setBrightness(0x0f);
sevSeg8.setBrightness(0x0f);
sevSeg9.setBrightness(0x0f);
sevSeg10.setBrightness(0x0f);
sevSeg11.setBrightness(0x0f);
sevSeg12.setBrightness(0x0f);
sevSeg13.setBrightness(0x0f);
sevSeg14.setBrightness(0x0f);
sevSeg15.setBrightness(0x0f);
sevSeg16.setBrightness(0x0f);
sevSeg17.setBrightness(0x0f);
sevSeg18.setBrightness(0x0f);
sevSeg19.setBrightness(0x0f);
sevSeg20.setBrightness(0x0f);
sevSeg21.setBrightness(0x0f);
sevSeg22.setBrightness(0x0f);
sevSeg23.setBrightness(0x0f);
sevSeg24.setBrightness(0x0f);
sevSeg25.setBrightness(0x0f);
sevSeg26.setBrightness(0x0f);
sevSeg27.setBrightness(0x0f);
sevSeg28.setBrightness(0x0f);
sevSeg29.setBrightness(0x0f);
sevSeg30.setBrightness(0x0f);
sevSeg31.setBrightness(0x0f);
sevSeg32.setBrightness(0x0f);
sevSeg33.setBrightness(0x0f);
}
void loop() {
DateTime now = rtc.now();
unsigned long nowUnix = now.unixtime();
// --- Cek apakah sudah waktunya alarm untuk salah satu jadwal ---
// Untuk mencegah pemicu berulang dalam satu menit, gunakan flag dengan menyimpan menit terakhir yang terpicu.
static int lastAlarmMinute = -1;
// Gunakan kondisi saat detik kurang dari 10 sebagai jendela trigger
if (now.second() < 10 && now.minute() != lastAlarmMinute) {
if ((now.hour() == sahurHour && now.minute() == sahurMinute) ||
(now.hour() == imsyakHour && now.minute() == imsyakMinute) ||
(now.hour() == subuhHour && now.minute() == subuhMinute) ||
(now.hour() == syuruqHour && now.minute() == syuruqMinute) ||
(now.hour() == ishraqHour && now.minute() == ishraqMinute) ||
(now.hour() == dzuhurHour && now.minute() == dzuhurMinute) ||
(now.hour() == asharHour && now.minute() == asharMinute) ||
(now.hour() == maghribHour && now.minute() == maghribMinute) ||
(now.hour() == isyaHour && now.minute() == isyaMinute))
{
lastAlarmMinute = now.minute();
}
// === Tampilan Waktu RTC (sama seperti sebelumnya) ===
int hh = now.hour();
int mm = now.minute();
int timeVal = hh * 100 + mm;
bool colonState = (millis() / 500) % 2 == 0;
sevSeg1.showNumberDecEx(timeVal, colonState ? 0x40 : 0, true);
int ss = now.second();
sevSeg2.clear();
sevSeg2.showNumberDec(ss, true, 2, 2);
int dd = now.day();
int mo = now.month();
int dateVal = dd * 100 + mo;
sevSeg3.showNumberDecEx(dateVal, 0x40, true);
int yyyy = now.year();
sevSeg4.showNumberDec(yyyy, true, 4, 0);
// === Waktu Sahur ===
DateTime sahurTime(now.year(), now.month(), now.day(), sahurHour, sahurMinute, 0);
if (now >= sahurTime) {
sahurTime = DateTime(sahurTime.year(), sahurTime.month(), sahurTime.day() + 1, sahurHour, sahurMinute, 0);
}
long totalSecondsSahur = sahurTime.unixtime() - nowUnix;
int countdownH_Sahur = totalSecondsSahur / 3600;
int countdownM_Sahur = (totalSecondsSahur % 3600) / 60;
int countdownS_Sahur = totalSecondsSahur % 60;
int sahurDisplay = sahurHour * 100 + sahurMinute;
bool sahurColon = (now.hour() == sahurHour && now.minute() == sahurMinute) ? ((millis() / 500) % 2 == 0) : false;
sevSeg5.showNumberDecEx(sahurDisplay, sahurColon ? 0x40 : 0, true);
int countdownHM_Sahur = countdownH_Sahur * 100 + countdownM_Sahur;
bool countdownColonSahur = (millis() / 500) % 2 == 0;
sevSeg6.showNumberDecEx(countdownHM_Sahur, countdownColonSahur ? 0x40 : 0, true);
sevSeg7.clear();
sevSeg7.showNumberDec(countdownS_Sahur, true, 2, 2);
// === Waktu Imsyak ===
DateTime imsyakTime(now.year(), now.month(), now.day(), imsyakHour, imsyakMinute, 0);
if (now >= imsyakTime) {
imsyakTime = DateTime(imsyakTime.year(), imsyakTime.month(), imsyakTime.day() + 1, imsyakHour, imsyakMinute, 0);
}
long totalSecondsImsyak = imsyakTime.unixtime() - nowUnix;
int countdownH_Imsyak = totalSecondsImsyak / 3600;
int countdownM_Imsyak = (totalSecondsImsyak % 3600) / 60;
int countdownS_Imsyak = totalSecondsImsyak % 60;
int imsyakDisplay = imsyakHour * 100 + imsyakMinute;
bool imsyakColon = (now.hour() == imsyakHour && now.minute() == imsyakMinute) ? ((millis() / 500) % 2 == 0) : false;
sevSeg8.showNumberDecEx(imsyakDisplay, imsyakColon ? 0x40 : 0, true);
int countdownHM_Imsyak = countdownH_Imsyak * 100 + countdownM_Imsyak;
bool countdownColonImsyak = (millis() / 500) % 2 == 0;
sevSeg9.showNumberDecEx(countdownHM_Imsyak, countdownColonImsyak ? 0x40 : 0, true);
sevSeg10.clear();
sevSeg10.showNumberDec(countdownS_Imsyak, true, 2, 2);
// === Waktu Subuh ===
DateTime subuhTime(now.year(), now.month(), now.day(), subuhHour, subuhMinute, 0);
if (now >= subuhTime) {
subuhTime = DateTime(subuhTime.year(), subuhTime.month(), subuhTime.day() + 1, subuhHour, subuhMinute, 0);
}
long totalSecondsSubuh = subuhTime.unixtime() - nowUnix;
int countdownH_Subuh = totalSecondsSubuh / 3600;
int countdownM_Subuh = (totalSecondsSubuh % 3600) / 60;
int countdownS_Subuh = totalSecondsSubuh % 60;
int subuhDisplay = subuhHour * 100 + subuhMinute;
bool subuhColon = (now.hour() == subuhHour && now.minute() == subuhMinute) ? ((millis() / 500) % 2 == 0) : false;
sevSeg11.showNumberDecEx(subuhDisplay, subuhColon ? 0x40 : 0, true);
int countdownHM_Subuh = countdownH_Subuh * 100 + countdownM_Subuh;
bool countdownColonSubuh = (millis() / 500) % 2 == 0;
sevSeg12.showNumberDecEx(countdownHM_Subuh, countdownColonSubuh ? 0x40 : 0, true);
sevSeg13.clear();
sevSeg13.showNumberDec(countdownS_Subuh, true, 2, 2);
// === Waktu Syuruq/Terbit ===
DateTime syuruqTime(now.year(), now.month(), now.day(), syuruqHour, syuruqMinute, 0);
if (now >= syuruqTime) {
syuruqTime = DateTime(syuruqTime.year(), syuruqTime.month(), syuruqTime.day() + 1, syuruqHour, syuruqMinute, 0);
}
long totalSecondsSyuruq = syuruqTime.unixtime() - nowUnix;
int countdownH_Syuruq = totalSecondsSyuruq / 3600;
int countdownM_Syuruq = (totalSecondsSyuruq % 3600) / 60;
int countdownS_Syuruq = totalSecondsSyuruq % 60;
int syuruqDisplay = syuruqHour * 100 + syuruqMinute;
bool syuruqColon = (now.hour() == syuruqHour && now.minute() == syuruqMinute) ? ((millis() / 500) % 2 == 0) : false;
sevSeg14.showNumberDecEx(syuruqDisplay, syuruqColon ? 0x40 : 0, true);
int countdownHM_Syuruq = countdownH_Syuruq * 100 + countdownM_Syuruq;
bool countdownColonSyuruq = (millis() / 500) % 2 == 0;
sevSeg15.showNumberDecEx(countdownHM_Syuruq, countdownColonSyuruq ? 0x40 : 0, true);
sevSeg16.clear();
sevSeg16.showNumberDec(countdownS_Syuruq, true, 2, 2);
// === Waktu Baru (tanpa TimeSpan) ===
auto getTargetUnix = [&](int hr, int mn) -> unsigned long {
unsigned long t = DateTime(now.year(), now.month(), now.day(), hr, mn, 0).unixtime();
if(nowUnix >= t) t += 86400UL;
return t;
};
// --- Ishraq/Dhuha ---
unsigned long targetIshraq = getTargetUnix(ishraqHour, ishraqMinute);
unsigned long diffIshraq = targetIshraq - nowUnix;
int ishraqCountH = diffIshraq / 3600;
int ishraqCountM = (diffIshraq % 3600) / 60;
int ishraqCountS = diffIshraq % 60;
int ishraqDisplay = ishraqHour * 100 + ishraqMinute;
bool ishraqColon = (now.hour() == ishraqHour && now.minute() == ishraqMinute) ? ((millis()/500)%2==0) : false;
sevSeg17.showNumberDecEx(ishraqDisplay, ishraqColon ? 0x40 : 0, true);
int countdownIshraqHM = ishraqCountH * 100 + ishraqCountM;
bool countdownIshraqColon = (millis()/500)%2==0;
sevSeg18.showNumberDecEx(countdownIshraqHM, countdownIshraqColon ? 0x40 : 0, true);
sevSeg19.clear();
sevSeg19.showNumberDec(ishraqCountS, true, 2, 2);
// --- Dzuhur/Jumat ---
unsigned long targetDzuhur = getTargetUnix(dzuhurHour, dzuhurMinute);
unsigned long diffDzuhur = targetDzuhur - nowUnix;
int dzuhurCountH = diffDzuhur / 3600;
int dzuhurCountM = (diffDzuhur % 3600) / 60;
int dzuhurCountS = diffDzuhur % 60;
int dzuhurDisplay = dzuhurHour * 100 + dzuhurMinute;
bool dzuhurColon = (now.hour() == dzuhurHour && now.minute() == dzuhurMinute) ? ((millis()/500)%2==0) : false;
sevSeg20.showNumberDecEx(dzuhurDisplay, dzuhurColon ? 0x40 : 0, true);
int countdownDzuhurHM = dzuhurCountH * 100 + dzuhurCountM;
bool countdownDzuhurColon = (millis()/500)%2==0;
sevSeg21.showNumberDecEx(countdownDzuhurHM, countdownDzuhurColon ? 0x40 : 0, true);
sevSeg22.clear();
sevSeg22.showNumberDec(dzuhurCountS, true, 2, 2);
// --- Ashar ---
unsigned long targetAshar = getTargetUnix(asharHour, asharMinute);
unsigned long diffAshar = targetAshar - nowUnix;
int asharCountH = diffAshar / 3600;
int asharCountM = (diffAshar % 3600) / 60;
int asharCountS = diffAshar % 60;
int asharDisplay = asharHour * 100 + asharMinute;
bool asharColon = (now.hour() == asharHour && now.minute() == asharMinute) ? ((millis()/500)%2==0) : false;
sevSeg23.showNumberDecEx(asharDisplay, asharColon ? 0x40 : 0, true);
int countdownAsharHM = asharCountH * 100 + asharCountM;
bool countdownAsharColon = (millis()/500)%2==0;
sevSeg24.showNumberDecEx(countdownAsharHM, countdownAsharColon ? 0x40 : 0, true);
sevSeg25.clear();
sevSeg25.showNumberDec(asharCountS, true, 2, 2);
// --- Maghrib ---
unsigned long targetMaghrib = getTargetUnix(maghribHour, maghribMinute);
unsigned long diffMaghrib = targetMaghrib - nowUnix;
int maghribCountH = diffMaghrib / 3600;
int maghribCountM = (diffMaghrib % 3600) / 60;
int maghribCountS = diffMaghrib % 60;
int maghribDisplay = maghribHour * 100 + maghribMinute;
bool maghribColon = (now.hour() == maghribHour && now.minute() == maghribMinute) ? ((millis()/500)%2==0) : false;
sevSeg26.showNumberDecEx(maghribDisplay, maghribColon ? 0x40 : 0, true);
int countdownMaghribHM = maghribCountH * 100 + maghribCountM;
bool countdownMaghribColon = (millis()/500)%2==0;
sevSeg27.showNumberDecEx(countdownMaghribHM, countdownMaghribColon ? 0x40 : 0, true);
sevSeg28.clear();
sevSeg28.showNumberDec(maghribCountS, true, 2, 2);
// --- Isya ---
unsigned long targetIsya = getTargetUnix(isyaHour, isyaMinute);
unsigned long diffIsya = targetIsya - nowUnix;
int isyaCountH = diffIsya / 3600;
int isyaCountM = (diffIsya % 3600) / 60;
int isyaCountS = diffIsya % 60;
int isyaDisplay = isyaHour * 100 + isyaMinute;
bool isyaColon = (now.hour() == isyaHour && now.minute() == isyaMinute) ? ((millis()/500)%2==0) : false;
sevSeg29.showNumberDecEx(isyaDisplay, isyaColon ? 0x40 : 0, true);
int countdownIsyaHM = isyaCountH * 100 + isyaCountM;
bool countdownIsyaColon = (millis()/500)%2==0;
sevSeg30.showNumberDecEx(countdownIsyaHM, countdownIsyaColon ? 0x40 : 0, true);
sevSeg31.clear();
sevSeg31.showNumberDec(isyaCountS, true, 2, 2);
// --- Iqomah (9 menit countdown) ---
int iqomahDiff = -1; // jika aktif, selisih detik menuju akhir periode iqomah
unsigned long subuhScheduled = DateTime(now.year(), now.month(), now.day(), subuhHour, subuhMinute, 0).unixtime();
if(nowUnix >= subuhScheduled && nowUnix < subuhScheduled + iqomahDuration) {
iqomahDiff = (subuhScheduled + iqomahDuration) - nowUnix;
}
unsigned long dzuhurScheduled = DateTime(now.year(), now.month(), now.day(), dzuhurHour, dzuhurMinute, 0).unixtime();
if(iqomahDiff < 0 && nowUnix >= dzuhurScheduled && nowUnix < dzuhurScheduled + iqomahDuration) {
iqomahDiff = (dzuhurScheduled + iqomahDuration) - nowUnix;
}
unsigned long asharScheduled = DateTime(now.year(), now.month(), now.day(), asharHour, asharMinute, 0).unixtime();
if(iqomahDiff < 0 && nowUnix >= asharScheduled && nowUnix < asharScheduled + iqomahDuration) {
iqomahDiff = (asharScheduled + iqomahDuration) - nowUnix;
}
unsigned long maghribScheduled = DateTime(now.year(), now.month(), now.day(), maghribHour, maghribMinute, 0).unixtime();
if(iqomahDiff < 0 && nowUnix >= maghribScheduled && nowUnix < maghribScheduled + iqomahDuration) {
iqomahDiff = (maghribScheduled + iqomahDuration) - nowUnix;
}
unsigned long isyaScheduled = DateTime(now.year(), now.month(), now.day(), isyaHour, isyaMinute, 0).unixtime();
if(iqomahDiff < 0 && nowUnix >= isyaScheduled && nowUnix < isyaScheduled + iqomahDuration) {
iqomahDiff = (isyaScheduled + iqomahDuration) - nowUnix;
}
if(iqomahDiff >= 0) {
int iqomahCountH = iqomahDiff / 3600;
int iqomahCountM = (iqomahDiff % 3600) / 60;
int iqomahCountS = iqomahDiff % 60;
int iqomahHM = iqomahCountH * 100 + iqomahCountM;
bool iqomahBlink = (iqomahDiff <= 5) ? ((millis()/500)%2==0) : false;
sevSeg32.showNumberDecEx(iqomahHM, iqomahBlink ? 0x40 : 0, true);
sevSeg33.clear();
sevSeg33.showNumberDec(iqomahCountS, true, 2, 2);
} else {
sevSeg32.clear();
sevSeg33.clear();
}
delay(100);
}
}