Reading it on an ESP32
An ESP32's ADC reads nothing below about 0.1 V at the Arduino core's default setting, and this block gives about 0.1 V at about 43 lux. So a dim room can read 0 on an ESP32 while an Uno reads a little. That is the floor, not a dead sensor. Read calibrated millivolts, and on an ESP32 use an ADC1 pin.
A floor under the reading
On an Uno or a Pico the ADC reads in a straight line from 0 V. An ESP32 and an ESP32-S3 do not. At the Arduino core's default setting their ADC returns 0 for anything below about 0.1 V, reads to about 3.1 V at the top, and is least straight near both ends. The exact edges differ from chip to chip, so the figure's ESP32 rows are illustrative.
For most blocks the floor costs a sliver at one end of the travel. For this one it lands in the middle of ordinary life. About 0.1 V is about 43 lux for a typical sensor: a dim room, a corridor, a lamp on the far side of the room. Slide the figure to 30 lux and the Uno and Pico read a little while both ESP32s read 0.
So a 0 on an ESP32 in a dim room is the floor, not a dead sensor. Shine a torch on it before suspecting the wiring.
Millivolts, not counts
A count means different things on different boards: out of 1023 against 5 V on an Uno, out of 4095 against the chip's own reference on an ESP32. The sketch above turns both into millivolts, so the same light prints about the same number on every board.
On an ESP32 it calls analogReadMilliVolts, which converts the count using
calibration data written into the chip at the factory. That straightens the
middle of the range. It cannot see below the floor: under about 100 mV the
number stops changing, because the converter measured nothing there.
On an Uno and a Pico the #else branch scales the count by the ADC's full
scale, 5000 mV or 3300 mV. For a typical sensor under the datasheet's light,
every 2.35 mV is about one lux.
ADC1 only
The classic ESP32 has two converters. ADC2 is shared with the radio, and while Wi-Fi is on its readings fail. GPIO 34, the pin used in this book, is on ADC1, which keeps working. So is GPIO 4 on the ESP32-S3: its ADC1 is GPIO 1 to 10.
The code
The same reading in millivolts, on every board. On an ESP32 or ESP32-S3 analogReadMilliVolts does the conversion with calibration stored in the chip; on an Uno or a Pico, the count is scaled by the ADC's full scale.
/*
Ambient Light Sensor - millivolts TK20 / /p/tk20
Wiring. Count from the square pad on the TinkerBlock board, parts
up, header at the bottom:
GND -> GND
VCC -> 5V on an Uno; 3V3 on an ESP32, ESP32-S3 or Pico
NC -> nothing (unconnected on the board)
SIGNAL -> A0 on an Uno, GPIO 34 on an ESP32, GPIO 4 on an
ESP32-S3, GP26 on a Raspberry Pi Pico
Arduino IDE
Tools > Board your board, e.g. ESP32S3 Dev Module
Tools > Port the one that appears when you plug in
Tools > USB CDC On Boot Enabled (ESP32-S3 only)
No library needed.
*/
// The analog pin SIGNAL is wired to.
// Uno: A0. ESP32: 34. ESP32-S3: 4. Pico: 26.
const int LIGHT_PIN = A0;
// Uno and Pico only: the ADC's full scale, in mV.
// Uno: 5000. Pico: 3300.
const float FULL_SCALE_MV = 5000.0;
float readMilliVolts() {
#if defined(ARDUINO_ARCH_ESP32)
return analogReadMilliVolts(LIGHT_PIN); // calibrated in the chip
#else
return analogRead(LIGHT_PIN) * FULL_SCALE_MV / 1023.0;
#endif
}
void setup() {
Serial.begin(115200);
}
void loop() {
float mv = readMilliVolts(); // more light, higher
Serial.print(mv, 0);
Serial.println(" mV");
delay(500);
}For a typical sensor under the datasheet's light, 2.35 mV is about one lux, so 235 mV is about 100 lux. Take that as a rough guide only: one sensor can be 30 % off, and a different kind of light changes it more. Below about 100 mV an ESP32 cannot tell values apart.
Millivolts in MicroPython. On an ESP32 read_uv returns calibrated microvolts; on a Pico the 16-bit count is scaled by 3.3 V.
"""
Ambient Light Sensor - millivolts, MicroPython TK20 / /p/tk20
Wiring. Count from the square pad on the TinkerBlock board, parts
up, header at the bottom:
GND -> GND
VCC -> 3V3 (never 5V: bright light takes SIGNAL towards VCC)
NC -> nothing (unconnected on the board)
SIGNAL -> GPIO 34 on an ESP32, GPIO 4 on an ESP32-S3,
GP26 on a Raspberry Pi Pico
Thonny
Run > Configure interpreter MicroPython (ESP32) or
MicroPython (Raspberry Pi Pico)
Save it to the board as main.py to run it on every power-up.
Nothing to install: machine, sys and time are built in.
"""
import sys
import time
from machine import ADC, Pin
# The GPIO number SIGNAL is wired to. ESP32: 34. ESP32-S3: 4. Pico: 26.
LIGHT_PIN = 4
adc = ADC(Pin(LIGHT_PIN))
ESP = sys.platform == "esp32" # ESP32 and ESP32-S3
if ESP:
adc.atten(ADC.ATTN_11DB) # the full range, to about 3.1 V
def read_millivolts():
if ESP:
return adc.read_uv() / 1000 # calibrated in the chip
return adc.read_u16() * 3300 / 65535
while True:
print("%.0f mV" % read_millivolts()) # more light, higher
time.sleep_ms(500)There is no Uno here: an Uno cannot run MicroPython. The atten line matters: without it MicroPython's ESP32 ADC stops near 1 V, and ordinary daylight is off the top. Stop it with Ctrl-C.
When it does not work
Under about 43 lux a typical sensor puts less than about 0.1 V on SIGNAL, and an ESP32's ADC cannot see that. Shine a torch on the sensor: if the number jumps, the block is fine. For a night light that has to work in a dim room, the switching point needs to sit above the floor, which the night-light article's calibration shows you.
It is part of Espressif's ESP32 Arduino core, in the 2.x and 3.x releases. An older core, or a board package that is not Espressif's, may not have it. Update the core in the Boards Manager. On an Uno or a Pico the sketch never calls it: the #if sends them down the analogRead path.
SIGNAL is on an ADC2 pin. On the classic ESP32 the radio uses ADC2 while Wi-Fi is on, and readings from it fail or return rubbish. Move SIGNAL to an ADC1 pin: GPIO 34 here, or any of GPIO 32 to 39.
The sketch assumes the Uno's 5V pin is exactly 5000 mV. On USB it is often a little under. Measure the 5V pin while the board runs and put that into FULL_SCALE_MV. The ESP32's figure does not need this: analogReadMilliVolts uses its own calibration.
Why a filament bulb reads so much higher than an LED that looks just as bright.
It sees infrared →Edit this page — content/books/ambient-light-sensor/reading-it-on-an-esp32.mdx
Questions about this product
See what other owners have asked, and read their solutions.
Ambient Light Sensor
Loading discussions…
Discuss this article
Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.