/*
Project: Lampu Tidur ESP32 dengan Sensor Tepuk (LDR), LCD I2C, dan Alarm Jam Internal (tanpa RTC)
Deskripsi:
- Sensor LDR dipakai sebagai pengganti sensor suara
- Saat nilai LDR berubah cepat (simulasi tepuk), lampu akan toggle (nyala/mati)
- Jam diambil dari waktu internal NTP (tanpa modul RTC)
- Alarm diset via Serial, contoh: SET 05:00
- Saat waktu sesuai, buzzer bunyi dan lampu mati otomatis
*/
#include <WiFi.h>
#include "time.h"
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// ====== Konfigurasi ======
const char* WIFI_SSID = "YOUR_WIFI_SSID";
const char* WIFI_PASS = "YOUR_WIFI_PASSWORD";
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 7 * 3600; // UTC+7 (WIB)
const int daylightOffset_sec = 0;
// ====== Pin Setup (sesuai gambar) ======
#define PIN_LDR 34 // AO dari sensor LDR
#define PIN_LAMP 2 // LED
#define PIN_BUZZER 15 // Buzzer
#define SDA_PIN 21
#define SCL_PIN 22
// ====== Konstanta ======
#define CLAP_DELTA_THRESHOLD 120
#define CLAP_DEBOUNCE_MS 400
// ====== Variabel ======
bool lampState = false;
int lastLdrValue = 0;
unsigned long lastClapTime = 0;
bool alarmEnabled = false;
bool alarmTriggeredToday = false;
int alarmHour = -1;
int alarmMinute = -1;
// ====== LCD I2C ======
LiquidCrystal_I2C lcd(0x27, 16, 2);
// ====== Buzzer ======
#define BUZZER_CHANNEL 0
#define BUZZER_FREQ 2000
#define BUZZER_RESOLUTION 8
void setup() {
Serial.begin(115200);
delay(1000);
// Setup pin
pinMode(PIN_LAMP, OUTPUT);
digitalWrite(PIN_LAMP, LOW);
pinMode(PIN_BUZZER, OUTPUT);
// Setup buzzer PWM
ledcSetup(BUZZER_CHANNEL, BUZZER_FREQ, BUZZER_RESOLUTION);
ledcAttachPin(PIN_BUZZER, BUZZER_CHANNEL);
ledcWrite(BUZZER_CHANNEL, 0);
// Setup LCD
Wire.begin(SDA_PIN, SCL_PIN);
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Connecting WiFi");
// Setup WiFi dan waktu
connectWiFi();
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
delay(1000);
lcd.clear();
lcd.print("Ready...");
lastLdrValue = analogRead(PIN_LDR);
Serial.println("=== Sistem Siap ===");
Serial.println("Perintah: SET hh:mm | OFF | STATUS");
}
void loop() {
checkClap();
displayTime();
checkAlarm();
handleSerial();
delay(100);
}
// ====== Fungsi ======
void connectWiFi() {
WiFi.begin(WIFI_SSID, WIFI_PASS);
Serial.print("Connecting");
int retry = 0;
while (WiFi.status() != WL_CONNECTED && retry < 30) {
delay(500);
Serial.print(".");
retry++;
}
Serial.println();
if (WiFi.status() == WL_CONNECTED) {
Serial.println("WiFi Connected!");
lcd.clear();
lcd.print("WiFi Connected");
} else {
Serial.println("WiFi Failed!");
lcd.clear();
lcd.print("WiFi Failed");
}
}
void checkClap() {
int ldrValue = analogRead(PIN_LDR);
int delta = abs(ldrValue - lastLdrValue);
if (delta > CLAP_DELTA_THRESHOLD && (millis() - lastClapTime > CLAP_DEBOUNCE_MS)) {
lastClapTime = millis();
lampState = !lampState;
digitalWrite(PIN_LAMP, lampState ? HIGH : LOW);
Serial.printf("Clap detected! Lamp %s\n", lampState ? "ON" : "OFF");
}
lastLdrValue = ldrValue;
}
void displayTime() {
struct tm timeinfo;
if (getLocalTime(&timeinfo)) {
lcd.setCursor(0, 0);
lcd.printf("%02d:%02d:%02d ", timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
lcd.setCursor(0, 1);
if (alarmEnabled)
lcd.printf("Alarm %02d:%02d ", alarmHour, alarmMinute);
else
lcd.print("Alarm OFF ");
} else {
lcd.setCursor(0, 0);
lcd.print("No Time Data ");
}
}
void checkAlarm() {
if (!alarmEnabled) return;
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) return;
if (timeinfo.tm_hour == alarmHour && timeinfo.tm_min == alarmMinute && !alarmTriggeredToday) {
alarmTriggeredToday = true;
Serial.println("Alarm triggered!");
lampState = false;
digitalWrite(PIN_LAMP, LOW);
soundAlarm();
}
if (timeinfo.tm_hour == 0 && timeinfo.tm_min == 0)
alarmTriggeredToday = false;
}
void soundAlarm() {
unsigned long start = millis();
while (millis() - start < 10000) {
ledcWrite(BUZZER_CHANNEL, 200);
delay(300);
ledcWrite(BUZZER_CHANNEL, 0);
delay(300);
}
ledcWrite(BUZZER_CHANNEL, 0);
Serial.println("Alarm stopped.");
}
void handleSerial() {
if (!Serial.available()) return;
String line = Serial.readStringUntil('\n');
line.trim();
line.toUpperCase();
if (line.startsWith("SET ")) {
int colon = line.indexOf(':');
if (colon > 0) {
alarmHour = line.substring(4, colon).toInt();
alarmMinute = line.substring(colon + 1).toInt();
alarmEnabled = true;
alarmTriggeredToday = false;
Serial.printf("Alarm set to %02d:%02d\n", alarmHour, alarmMinute);
} else {
Serial.println("Format salah! Gunakan: SET hh:mm");
}
} else if (line == "OFF") {
alarmEnabled = false;
Serial.println("Alarm dimatikan.");
} else if (line == "STATUS") {
Serial.printf("Lamp: %s | Alarm: %s %02d:%02d\n",
lampState ? "ON" : "OFF",
alarmEnabled ? "ON" : "OFF",
alarmHour, alarmMinute);
} else {
Serial.println("Perintah tidak dikenal. Gunakan: SET hh:mm | OFF | STATUS");
}
}