BH1750 Digital Light Sensor

How to measure light intensity with the BH1750 sensor and ESP32

The BH1750 is a digital ambient light sensor that measures illuminance (light intensity) in lux and communicates over I2C. Unlike a simple photoresistor (LDR), the BH1750 outputs a calibrated digital value directly in lux, so there is no need for analog-to-digital conversion or manual calibration. It is an ideal sensor for projects that need accurate, repeatable light measurements.

This guide uses the ESP32-WROOM-32 DevKit. Pin labels may differ on your board -- check your board's pinout diagram.

Alternatives: For simple light/dark detection where calibrated lux values are not needed, an LDR is cheaper and simpler (no library, no I2C). See our light sensor comparison for a full breakdown.

🔗Key Specs

ParameterValue
Measurement range$1$ to $65535\,\text{lx}$
Resolution$1\,\text{lx}$ (high-resolution mode)
AccuracyVaries; close to human eye response
Supply voltage$2.4$ to $3.6\,\text{V}$
InterfaceI2C
I2C address0x23 (ADDR low) or 0x5C (ADDR high)

🔗What Is Lux?

Lux (lx) is the standard unit of illuminance -- it measures how much light falls on a surface. Here are some reference values to give you an intuitive sense:

ConditionApproximate Lux
Direct sunlight$30{,}000 - 100{,}000\,\text{lx}$
Overcast daylight$10{,}000 - 25{,}000\,\text{lx}$
Office lighting$300 - 500\,\text{lx}$
Living room$100 - 300\,\text{lx}$
Twilight$\approx 10\,\text{lx}$
Full moon$\approx 0.25\,\text{lx}$

These values are useful for setting thresholds in your projects -- for example, turning on a light when the reading drops below $200\,\text{lx}$.

🔗What You'll Need

ComponentQtyNotesBuy
ESP32 dev board1AliExpress | Amazon.de .co.uk .com
BH1750 light sensor1AliExpress | Amazon.de .co.uk .com
Breadboard1AliExpress | Amazon.de .co.uk .com
Jumper wires5AliExpress | Amazon.de .co.uk .com

Links marked Amazon/AliExpress are affiliate links. We may earn a small commission at no extra cost to you.

🔗Wiring (I2C)

BH1750 PinESP32 PinNotes
VCC3.3VDo not use 5V
GNDGND
SDAGPIO 21Default I2C data line on ESP32
SCLGPIO 22Default I2C clock line on ESP32
ADDRGNDSets address to 0x23 (connect to VCC for 0x5C)

Pin labels, GPIO numbers, and ADC channels vary between ESP32 boards. GPIOs 21 (SDA) and 22 (SCL) are the default I2C pins on most ESP32-WROOM-32 DevKit boards, but your board may differ. Always check your board's pinout diagram.

🔗I2C Address

The ADDR pin controls the I2C address:

  • ADDR connected to GND (or left floating): address is 0x23
  • ADDR connected to VCC: address is 0x5C

This lets you use two BH1750 sensors on the same I2C bus with different addresses.

🔗Required Libraries

Install the following through the Arduino Library Manager:

  1. BH1750 by Christopher Laws -- provides a straightforward API for the sensor

To install:

  1. Go to Sketch > Include Library > Manage Libraries...
  2. Search for BH1750 and install the library by Christopher Laws

No additional dependencies are needed beyond the built-in Wire.h library.

🔗Code Example

This sketch reads the light level in lux from the BH1750 sensor and prints it to the Serial Monitor every second.

#include <Wire.h>
#include <BH1750.h>

BH1750 lightMeter;

void setup() {
    Serial.begin(115200);
    Wire.begin();  // Initialize I2C (SDA = GPIO 21, SCL = GPIO 22)

    if (lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE)) {
        Serial.println("BH1750 sensor initialized.");
    } else {
        Serial.println("Error: Could not find BH1750 sensor.");
        Serial.println("Check wiring and I2C address.");
        while (1) delay(10);  // Halt
    }
}

void loop() {
    float lux = lightMeter.readLightLevel();

    if (lux < 0) {
        Serial.println("Error reading light level.");
    } else {
        Serial.print("Light: ");
        Serial.print(lux, 1);
        Serial.println(" lx");
    }

    delay(1000);
}

🔗Using Two Sensors

If you connect two BH1750 sensors with different ADDR settings, you can read both:

BH1750 lightMeter1(0x23);  // ADDR = GND
BH1750 lightMeter2(0x5C);  // ADDR = VCC

void setup() {
    Serial.begin(115200);
    Wire.begin();
    lightMeter1.begin(BH1750::CONTINUOUS_HIGH_RES_MODE);
    lightMeter2.begin(BH1750::CONTINUOUS_HIGH_RES_MODE);
}

void loop() {
    float lux1 = lightMeter1.readLightLevel();
    float lux2 = lightMeter2.readLightLevel();

    Serial.print("Sensor 1: ");
    Serial.print(lux1, 1);
    Serial.print(" lx  |  Sensor 2: ");
    Serial.print(lux2, 1);
    Serial.println(" lx");

    delay(1000);
}

🔗How It Works

The BH1750 contains an integrated photodiode and a 16-bit analog-to-digital converter. It measures the intensity of visible light hitting the sensor and converts it to a digital lux value internally. The sensor's spectral response is designed to approximate the sensitivity of the human eye, which makes its readings feel intuitive.

In continuous high-resolution mode (the default in our code), the sensor takes a new reading approximately every $120\,\text{ms}$ and makes the latest value available over I2C whenever you request it.

🔗Troubleshooting

ProblemPossible CauseSolution
"Could not find BH1750"Wrong I2C addressCheck the ADDR pin; try 0x5C if ADDR is connected to VCC
"Could not find BH1750"Wiring issueVerify SDA, SCL, VCC, and GND connections
Always reads 0 lxSensor in power-down modeEnsure begin() is called with a valid mode
Readings are very noisyElectrical interferenceUse shorter I2C wires; add pull-up resistors if not on module
Reads max value (65535 lx)Sensor saturated by very bright lightNormal for direct sunlight; consider shading the sensor
Reads negative valueI2C communication errorCheck wiring; reduce I2C clock speed

🔗Next Steps

  • Build an automatic desk lamp that adjusts brightness based on ambient light levels
  • Create a daylight logger that tracks light levels throughout the day
  • Combine the BH1750 with a relay to control outdoor lights at dusk
  • Pair it with a BME280 for a complete environmental monitoring station