
Đèn chiếu sáng thông minh tự động theo ánh sáng và lịch giờ
ESP32 tự động bật/tắt đèn LED/relay dựa trên cảm biến ánh sáng LDR và khung giờ lịch đồng bộ qua NTP — chỉ sáng khi trời tối và đúng khung giờ cấu hình.
Dự án này biến một bóng đèn/dải LED thường thành đèn chiếu sáng "thông minh": ESP32 đọc giá trị ánh sáng môi trường qua cảm biến quang trở LDR, đồng thời đồng bộ thời gian thực qua NTP để biết khung giờ hiện tại.
Đèn chỉ tự động BẬT khi trời đủ tối và đang trong khung giờ lịch cấu hình (ví dụ 18:00–23:00).
Hướng dẫn chi tiết
ESP32 tự động bật/tắt đèn dựa trên cảm biến LDR và khung giờ lịch NTP — hướng dẫn đầy đủ 8 mục, sơ đồ đấu nối và code compile pass.
1. Giới thiệu
Dự án này biến một dải LED 12V/5V thành đèn chiếu sáng "thông minh": ESP32 đọc giá trị ánh sáng môi trường qua cảm biến quang trở LDR, đồng thời đồng bộ thời gian thực qua NTP để biết khung giờ hiện tại. Dùng dải LED 12V/5V làm chuẩn giúp bạn thực hành an toàn tuyệt đối, không rủi ro điện giật.
Đèn chỉ tự động BẬT khi trời đủ tối và đang trong khung giờ lịch cấu hình (ví dụ 18:00–23:00), tránh bật nhầm ban ngày dù trời âm u, và tránh sáng đèn suốt đêm ngoài khung giờ mong muốn.
2. Linh kiện cần có
| Linh kiện | Số lượng | Ghi chú |
|---|---|---|
| ESP32 DevKit V4 | 1 | Board chính, xử lý logic + WiFi |
| LDR – Cảm biến quang trở (mod_ldr_analog) | 1 | Đọc mức ánh sáng qua ngõ ra Analog (AO) |
| Relay Module 1 kênh 5V (mod_relay_1ch) | 1 | Đóng/ngắt nguồn dải LED, active-low |
| Dải LED 12V (hoặc đèn LED 5V) + nguồn adapter riêng | 1 | Tải chuẩn của bài — an toàn, không rủi ro điện giật |
3. Sơ đồ kết nối
| Chân module | ESP32 |
|---|---|
| LDR VCC | 3V3 |
| LDR GND | GND |
| LDR AO | GPIO34 (ADC input-only) |
| Relay VCC | 5V |
| Relay GND | GND |
| Relay IN | GPIO26 |
| Relay NO/COM | Dây dương (+) của dải LED 12V/5V, nguồn lấy từ adapter riêng — không lấy từ ESP32 |
Ghi chú: Relay module chỉ cần 5V/GND/IN nối với ESP32 — hai chân NO/COM nối trực tiếp vào dây nguồn dải LED (nguồn ngoài), tuyệt đối không đấu điện AC vào chân GPIO của ESP32. Ngưỡng DARK_THRESHOLD nên được hiệu chỉnh thực tế theo mạch phân áp LDR cụ thể.
4. Code ví dụ #1 — Đọc cảm biến ánh sáng LDR (ADC)
void setup() {
Serial.begin(115200);
pinMode(PIN_LDR_AO, INPUT);
}
void loop() {
int ldrValue = analogRead(PIN_LDR_AO); // 0-4095, càng thấp càng tối
bool isDark = ldrValue < DARK_THRESHOLD;
Serial.printf("ldr=%d dark=%s\n", ldrValue, isDark ? "true" : "false");
delay(500);
}5. Code ví dụ #2 — Điều khiển relay theo ánh sáng + lịch NTP
void setRelay(bool on) {
// Relay active-low: IN=LOW => kích hoạt (đóng NO, bật đèn)
digitalWrite(PIN_RELAY_IN, on ? LOW : HIGH);
relayState = on;
}
bool inSchedule(struct tm &timeinfo) {
int hour = timeinfo.tm_hour;
return (hour >= SCHEDULE_START_HOUR && hour < SCHEDULE_END_HOUR);
}
// Trong loop(): bật đèn khi VỪA tối VỪA trong khung giờ lịch
bool shouldTurnOn = isDark && inSchedule(timeinfo);
if (shouldTurnOn != relayState) setRelay(shouldTurnOn);6. Code ví dụ #3 — Ứng dụng thực tế đầy đủ — WiFi + NTP + LDR + Relay
/*
Đèn chiếu sáng thông minh tự động theo ánh sáng và lịch giờ
Board: ESP32 DevKit V4 (board_esp32_devkitc)
- LDR (mod_ldr_analog) AO -> GPIO34
- Relay 1 kênh (mod_relay_1ch) IN -> GPIO26 (điều khiển dải LED 12V/5V qua tải DC)
Đèn sẽ bật khi: trời tối (LDR đọc dưới ngưỡng) VÀ đang trong khung giờ lịch (vd 18:00-23:00).
Ngoài khung giờ hoặc trời đủ sáng -> tắt.
*/
#include <WiFi.h>
#include <time.h>
const char *WIFI_SSID = "YOUR_WIFI_SSID";
const char *WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";
const int PIN_LDR_AO = 34;
const int PIN_RELAY_IN = 26;
const int DARK_THRESHOLD = 1800;
const int SCHEDULE_START_HOUR = 18;
const int SCHEDULE_END_HOUR = 23;
const char *NTP_SERVER = "pool.ntp.org";
const long GMT_OFFSET_SEC = 7 * 3600;
const int DAYLIGHT_OFFSET_SEC = 0;
const unsigned long WIFI_RETRY_INTERVAL_MS = 5000;
const unsigned long WIFI_CONNECT_TIMEOUT_MS = 10000;
const unsigned long TELEMETRY_INTERVAL_MS = 5000;
unsigned long lastWifiAttemptMs = 0;
unsigned long lastTelemetryMs = 0;
bool relayState = false;
bool ntpSynced = false;
void connectWiFiNonBlocking() {
if (WiFi.status() == WL_CONNECTED) return;
unsigned long now = millis();
if (now - lastWifiAttemptMs < WIFI_RETRY_INTERVAL_MS) return;
lastWifiAttemptMs = now;
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
unsigned long start = millis();
while (WiFi.status() != WL_CONNECTED && millis() - start < WIFI_CONNECT_TIMEOUT_MS) {
delay(200);
}
if (WiFi.status() == WL_CONNECTED) {
if (!ntpSynced) {
configTime(GMT_OFFSET_SEC, DAYLIGHT_OFFSET_SEC, NTP_SERVER);
struct tm timeinfo;
if (getLocalTime(&timeinfo, 5000)) {
ntpSynced = true;
}
}
}
}
void setRelay(bool on) {
digitalWrite(PIN_RELAY_IN, on ? LOW : HIGH);
relayState = on;
}
void setup() {
Serial.begin(115200);
delay(300);
pinMode(PIN_LDR_AO, INPUT);
pinMode(PIN_RELAY_IN, OUTPUT);
setRelay(false);
connectWiFiNonBlocking();
}
void loop() {
connectWiFiNonBlocking();
int ldrValue = analogRead(PIN_LDR_AO);
bool isDark = ldrValue < DARK_THRESHOLD;
bool inSchedule = false;
struct tm timeinfo;
bool haveTime = ntpSynced && getLocalTime(&timeinfo, 10);
if (haveTime) {
int hour = timeinfo.tm_hour;
inSchedule = (hour >= SCHEDULE_START_HOUR && hour < SCHEDULE_END_HOUR);
}
bool shouldTurnOn = isDark && inSchedule;
if (shouldTurnOn != relayState) {
setRelay(shouldTurnOn);
}
delay(200);
}
7. Lỗi thường gặp
| Lỗi | Nguyên nhân | Cách sửa |
|---|---|---|
| LDR luôn đọc giá trị cố định (0 hoặc 4095) | Sai chân AO, hoặc dùng nhầm chân input-only cho việc khác | Kiểm tra lại GPIO34 chưa bị chiếm dụng, đo thử bằng multimeter chân AO khi che/hở sáng |
| Relay kêu tách nhưng đèn không sáng | Đấu nhầm NO/NC, hoặc tải vượt dòng relay cho phép | Dùng chân NO cho mạch cần bật khi kích hoạt; kiểm tra dòng tải phù hợp dải LED |
| Không đồng bộ được NTP (time luôn 1970) | WiFi timeout trước khi configTime() kịp chạy | Thử server NTP khác (vd time.google.com), đảm bảo mạng không chặn UDP 123 |
| Đèn bật/tắt nhấp nháy liên tục quanh ngưỡng tối | Giá trị LDR dao động quanh DARK_THRESHOLD không có hysteresis | Thêm dải trễ (hysteresis) — ví dụ ngưỡng bật khác ngưỡng tắt ±100 |
8. Tổng kết
Bạn đã có một đèn chiếu sáng tự động theo cả điều kiện ánh sáng thực tế lẫn khung giờ mong muốn, dùng đúng 2 module phổ biến (LDR + Relay) với dải LED 12V/5V an toàn làm chuẩn, tận dụng NTP có sẵn trên ESP32.
Có thể mở rộng: thêm nhiều khung giờ, điều khiển qua app/MQTT, hoặc dùng PWM+MOSFET để dimming thay vì bật/tắt cứng.