The LDR module is a light-dependent resistor with an LM393 comparator on a small board, sold in nearly every starter kit for automatic street-light and night-lamp projects.
On the ESP32 DevKit V1 it runs straight from 3V3. The analog output goes to D33 (ADC1, so it still works with Wi-Fi) and the digital output to D27. The sketch reads both and runs the on-board blue LED as a night light with hysteresis, so it switches cleanly at dusk instead of flickering.
Wiring
| ESP32 DevKit V1 | LDR light sensor module | Wire | Notes |
|---|---|---|---|
| 3V3 | VCC | red | At 3.3 V both AO and DO stay inside the ESP32’s limits. |
| GND | GND | black | |
| D33 | AO | yellow | ADC1 — survives Wi-Fi. |
| D27 | DO | green | Digital only, so ADC2 doesn’t matter here. The module pulls DO up to its VCC. |
3.3–5 V part, 3.3 V board. AO swings up to VCC. On ESP32 and Pico, power the module from 3.3 V so AO never exceeds the ADC's 3.3 V limit; on Uno use 5 V.
Board quirks
- Two outputs, two uses: DO flips at the threshold you set with the blue pot (no code needed, but no hysteresis), and AO gives a value you can apply your own hysteresis to — the sketch switches on at 70 % darkness and off at 60 %, so a street light doesn’t flicker at dusk.
- Powering from VIN (5 V) would put up to 5 V on AO and DO. Keep it on 3V3.
- AO goes on D33 (ADC1). D25–D27, D4, D12–D15 are ADC2 and give no reading once Wi-Fi is on.
- The LDR’s response is logarithmic and the ESP32 ADC flattens below about 0.15 V and above about 3.1 V (11 dB attenuation). Treat the percentage as “darker / brighter”, not lux. For lux, use a BH1750.
- Most modules wire the LDR so AO falls as light increases; a few are the other way round. Cover the sensor with your finger and watch which way the millivolts go.
Code
// LDR light sensor module (LM393) on an ESP32 DevKit V1.
// VCC → 3V3, GND → GND, AO → D33 (GPIO33, ADC1), DO → D27 (GPIO27).
// On most modules AO falls as light rises, and DO goes LOW when it's brighter than the pot setting.
constexpr uint8_t AO_PIN = 33; // ADC1_CH5: works with Wi-Fi on
constexpr uint8_t DO_PIN = 27; // plain digital input (its ADC2 function isn't used)
constexpr uint8_t LED_PIN = 2; // on-board blue LED as a "night light"
// Hysteresis on the analog value so the light doesn't flicker at dusk.
constexpr int DARK_ON = 70; // % darkness to switch on
constexpr int DARK_OFF = 60; // % darkness to switch off
bool lightOn = false;
void setup() {
Serial.begin(115200);
pinMode(DO_PIN, INPUT); // the module has its own pull-up on DO
pinMode(LED_PIN, OUTPUT);
Serial.println("LDR module: AO on GPIO33, DO on GPIO27");
}
void loop() {
int mv = analogReadMilliVolts(AO_PIN);
int dark = constrain(map(mv, 100, 3100, 0, 100), 0, 100); // 0 % = bright, 100 % = dark
if (!lightOn && dark >= DARK_ON) lightOn = true;
if (lightOn && dark <= DARK_OFF) lightOn = false;
digitalWrite(LED_PIN, lightOn);
bool doBright = digitalRead(DO_PIN) == LOW;
Serial.printf("AO %4d mV Darkness %3d %% DO: %s Night light %s\n", mv, dark,
doBright ? "bright" : "dark ", lightOn ? "ON" : "off");
delay(500);
}// LDR light sensor module (LM393) on an ESP32 DevKit V1.
// VCC → 3V3, GND → GND, AO → D33 (GPIO33, ADC1), DO → D27 (GPIO27).
// On most modules AO falls as light rises, and DO goes LOW when it's brighter than the pot setting.
constexpr uint8_t AO_PIN = 33; // ADC1_CH5: works with Wi-Fi on
constexpr uint8_t DO_PIN = 27; // plain digital input (its ADC2 function isn't used)
constexpr uint8_t LED_PIN = 2; // on-board blue LED as a "night light"
// Hysteresis on the analog value so the light doesn't flicker at dusk.
constexpr int DARK_ON = 70; // % darkness to switch on
constexpr int DARK_OFF = 60; // % darkness to switch off
bool lightOn = false;
void setup() {
Serial.begin(115200);
pinMode(DO_PIN, INPUT); // the module has its own pull-up on DO
pinMode(LED_PIN, OUTPUT);
Serial.println("LDR module: AO on GPIO33, DO on GPIO27");
}
void loop() {
int mv = analogReadMilliVolts(AO_PIN);
int dark = constrain(map(mv, 100, 3100, 0, 100), 0, 100); // 0 % = bright, 100 % = dark
if (!lightOn && dark >= DARK_ON) lightOn = true;
if (lightOn && dark <= DARK_OFF) lightOn = false;
digitalWrite(LED_PIN, lightOn);
bool doBright = digitalRead(DO_PIN) == LOW;
Serial.printf("AO %4d mV Darkness %3d %% DO: %s Night light %s\n", mv, dark,
doBright ? "bright" : "dark ", lightOn ? "ON" : "off");
delay(500);
}Expected serial output
LDR module: AO on GPIO33, DO on GPIO27
AO 412 mV Darkness 10 % DO: bright Night light off
AO 2350 mV Darkness 75 % DO: dark Night light ON
AO 1950 mV Darkness 61 % DO: dark Night light ONLDR module: AO on GPIO33, DO on GPIO27 AO 412 mV Darkness 10 % DO: bright Night light off AO 2350 mV Darkness 75 % DO: dark Night light ON AO 1950 mV Darkness 61 % DO: dark Night light ON
Common errors
DO never changes
Turn the blue pot slowly while covering and uncovering the LDR; the DO LED on the module should toggle. If it doesn’t, the threshold is at one end.
AO reads 0 mV or 3300 mV all the time
AO on the wrong pin, or AO and DO swapped (DO is either 0 or 3.3 V). Check the print on your module — some put DO next to VCC.
Light switches off when a car passes at night
Headlights hit the LDR. Shade it so it sees the sky, not the road, and add a delay so the state must hold for a few seconds before switching.