ambient light sensor/Reading it/06. Reading it on an ESP32
Reading it · 06 of 10

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.

The same light on four boards
Light on the sensor30 lux
SIGNAL, 3V3
71 mV
ESP32 reads
0
ESP32 floor
about 43 lux
At 30 lux SIGNAL is about 71 mV, under the ESP32's floor of about 0.1 V, so both ESP32s read 0 while the Uno and Pico already read a little. Below about 43 lux a typical part gives an ESP32 nothing to read. That is the floor, not a dead sensor.

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.

light_millivolts.ino
/*
  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.

When it does not work

It reads 0 in my living room at night.

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.

analogReadMilliVolts does not compile.

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.

It worked until I turned Wi-Fi on.

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 millivolts on my Uno are a little off my multimeter.

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.

Where this goes next

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

Community

Questions about this product

See what other owners have asked, and read their solutions.

Ask a question ↗

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.

Browse Modules and blocks on the forum