// ====== Kontrol Otomatis Pencahayaan Ruangan (ESP32) ======
#include <Wire.h>
#include <RTClib.h>
#include <LiquidCrystal_I2C.h>
// ---------------- Pin Mapping (ESP32) ----------------
const int PIN_LDR = 34; // Analog input from LDR module (AO/OUT)
const int PIN_RELAY = 26; // Relay IN (active HIGH or LOW lihat modulmu)
const int PIN_LED = 33; // LED indikator via resistor 220Ω
// ---------------- I2C Device Addresses ----------------
const uint8_t LCD_ADDR = 0x27; // ganti ke 0x3F jika layar tidak muncul
// ---------------- Objects ----------------
RTC_DS3231 rtc;
LiquidCrystal_I2C lcd(LCD_ADDR, 16, 2);
// ---------------- Konfigurasi ----------------
// Jam penjadwalan lampu (24 jam)
const int ON_HOUR = 18; // mulai malam (18:00)
const int OFF_HOUR = 6; // akhir malam (06:00)
// Histeresis LDR (ADC ESP32: 0..4095). Sesuaikan dengan rangkaianmu.
// Misal bernilai makin besar = makin gelap (umum pada modul pembagi tegangan).
const int LDR_ON_THRESHOLD = 2600; // di atas ini dianggap gelap → ON (saat malam)
const int LDR_OFF_THRESHOLD = 2200; // di bawah ini dianggap cukup terang → OFF
// Relay aktif level (banyak modul relay aktif LOW). Ubah jika perlu.
const bool RELAY_ACTIVE_LEVEL = LOW; // LOW = ON, HIGH = OFF (relay aktif LOW)
// Jika modulmu aktif HIGH, set ke HIGH.
bool lampOn = false;
// Smoothing bacaan LDR
int readLDRSmooth(uint8_t samples = 10) {
long sum = 0;
for (uint8_t i = 0; i < samples; i++) {
sum += analogRead(PIN_LDR);
delay(2);
}
return sum / samples;
}
void setRelay(bool on) {
lampOn = on;
if (RELAY_ACTIVE_LEVEL == LOW) {
digitalWrite(PIN_RELAY, on ? LOW : HIGH);
} else {
digitalWrite(PIN_RELAY, on ? HIGH : LOW);
}
digitalWrite(PIN_LED, on ? HIGH : LOW);
}
void printLCD(const DateTime& now, int ldr) {
lcd.setCursor(0, 0);
// Format waktu: HH:MM:SS
char buf[17];
snprintf(buf, sizeof(buf), "%02d:%02d:%02d ", now.hour(), now.minute(), now.second());
lcd.print(buf);
// Sisa 6-7 karakter: tampilkan LDR (0..4095)
snprintf(buf, sizeof(buf), "L:%4d", ldr);
lcd.print(buf);
lcd.setCursor(0, 1);
// Status & mode
lcd.print(lampOn ? "LAMP:ON " : "LAMP:OFF");
bool isNight = (now.hour() >= ON_HOUR) || (now.hour() < OFF_HOUR);
lcd.print(isNight ? " Night" : " Day ");
}
void setup() {
// I2C pada ESP32 (SDA=21, SCL=22)
Wire.begin(21, 20);
pinMode(PIN_RELAY, OUTPUT);
pinMode(PIN_LED, OUTPUT);
pinMode(PIN_LDR, INPUT);
// Matikan dulu
setRelay(false);
// Serial opsional
Serial.begin(115200);
delay(200);
// LCD
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Auto Lighting");
lcd.setCursor(0, 1);
lcd.print("Init...");
// RTC
if (!rtc.begin()) {
lcd.clear();
lcd.print("RTC not found!");
while (true) {
// Tahan di sini agar jelas ada masalah pada RTC
delay(1000);
}
}
// Set waktu sekali saat pertama kali upload (lalu COMMENT baris ini)
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
lcd.clear();
}
void loop() {
DateTime now = rtc.now();
// Baca LDR
int ldr = readLDRSmooth(12);
// Tentukan siang/malam berdasarkan jam
bool isNight = (now.hour() >= ON_HOUR) || (now.hour() < OFF_HOUR);
// Logika kontrol dengan histeresis:
if (isNight) {
if (!lampOn && ldr >= LDR_ON_THRESHOLD) {
setRelay(true); // cukup gelap → nyalakan
} else if (lampOn && ldr <= LDR_OFF_THRESHOLD) {
setRelay(false); // cukup terang → matikan
}
} else {
// Siang → lampu harus OFF
if (lampOn) setRelay(false);
}
// Tampilkan di LCD
printLCD(now, ldr);
// Debug opsional
// Serial.printf("%02d:%02d LDR=%d Lamp=%d\n", now.hour(), now.minute(), ldr, lampOn);
delay(200); // refresh ~5x per detik
}