Skip to Content

Ambient Light Sensor BH1750 with Arduino

Ambient Light Sensor BH1750 with Arduino

In this tutorial you will learn how to use the Ambient Light Sensor BH1750, an OLED and an Arduino Uno to measure and display light intensity.

While you can use a simple light dependent resistor (LDR) to detect light, those sensor readings are not calibrated to a defined standard unit of light intensity. The BH1750 sensor on the other hand, measures light intensities in lux and therefore offers much more comparable measurements.

If you want to learn more, keep on reading.

Required Parts

I used an Arduino Uno for this project, but any other Arduino or any ESP32/ESP8266 board will work as well. As for the Light Sensor, I used the breakout board listed below but there is also a BH1750 sensor with a protective cap, which might be better for some practical applications.

Ambient Light Sensor BH1750

Arduino

Arduino Uno

USB Data Sync cable Arduino

USB Cable for Arduino UNO

Dupont wire set

Dupont Wire Set

Half_breadboard56a

Breadboard

OLED display

OLED Display

Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.

The BH1750 Ambient Light Sensor

The BH1750 Ambient Light Sensor is a digital light sensor that measures the intensity of light in its surroundings. It provides a I2C interface to communicate with microcontrollers like Arduino and ESP32. The sensor has a wide range of light sensitivity from 1 to 65535 lux, making it suitable for various lighting conditions.

One of the key features of the BH1750 sensor is its low power consumption (power-down current 0.01 µA), making it ideal for battery-powered devices. It also has a high resolution and can provide accurate light intensity readings. The sensor is easy to use and can be integrated into different DIY projects such as automatic lighting systems, smart agriculture, and weather stations. For more details information have a look at the datasheet:

Internally, the sensor chip contains a photodiode (PD) as light detector, a signal amplifier (AMP), a 16 bit analog-to-digital converter (ADC), and some logic to convert the ADC value in a light intensity measurement, and to send it via I2C. The following picture shows the block diagram:

Block Diagram of BH1750
Block Diagram of BH1750 (source)

BH1750 sensor breakout board

The sensor chip itself is tiny and for Arduino project you typically use a breakout board that has bigger pins, and a voltage regulator, and pullup resistors for the I2C interface on it. The voltage regulator allows you to run the sensor on 3.3V or 5V. The picture below shows the front and back of a typical BH1750 sensor breakout board:

Front and back of breakout board for BH1750
Front and back of breakout board for BH1750

You can see the power supply pins (VCC, GND), the I2C interface (SCL, SDA) and an ADDR pin. The ADDR pin can be used to set sensor’s I2C address. If you connect ADDR to VCC the sensor address will be 0x5C. Otherwise the (default) I2C address is 0x23.

Lux measurements

The sensor measures light intensity in lux, which according to Wikipedia is defined as follows:

The lux (symbol: lx) is the unit of illuminance, or luminous flux per unit area, in the International System of Units (SI). It is equal to one lumen per square meter. In photometry, this is used as a measure of the intensity, as perceived by the human eye, of light that hits or passes through a surface.

The following table shows Lux levels for different lighting conditions. If you use the BH1750 sensor to measure lux levels, note that the angle of the incoming light will affect the measurement.

Lux Levels
Lux Levels (source)

The datasheet contains the Spectral Response curve for the BH1750 and you can see that the sensor is most sensitive for light in the 500nm to 600nm wavelength range.

Spectral Response of BH1750
Spectral Response of BH1750 (source)

Connecting BH1750 to Arduino

Due to the I2C interface, connecting the BH1750 light sensor to an Arduino is very simple. First, connect the SCL and SDA pins of the BH1750 breakout board to the corresponding pins on the Arduino board as shown below. Next, connect ground and VCC.

Wiring of BH1750 sensor with Arduino
Wiring of BH1750 sensor with Arduino

Since the breakout board runs on 5V or 3.3V, you can use either for VCC; I went with 3.3V. In the next section, we will write some code to test the function of the sensor.

Code to measure Ambient Light with BH1750

We start by implementing some simple test code that prints out the light intensity measured by the BH1750 sensor.

#include "Wire.h"
#include "BH1750.h"

BH1750 luxMeter;

void setup(){
  Serial.begin(9600);
  Wire.begin();
  luxMeter.begin();
}

void loop() {
  float lux = luxMeter.readLightLevel();
  Serial.print("Light:");
  Serial.print(lux);
  Serial.println(" lx");
  delay(1000);
}

The code starts by including the required libraries. The Wire library is a standard library that comes with the Arduino core but the BH1750 library, you will have to install. Just open the Library Manager, search for BH1750 and install the BH1750 library by Christopher Laws as shown below:

BH1750 library by Christopher Laws in Library Manager
BH1750 library in Library Manager

There are several other libraries, and the BH1750 library by Rob Tillaart is an interesting alternative, since it has additional functions for temperature compensation, angle correction and asynchronous measurement.

In the setup function we initial the serial communication, the I2C communication via Wire and the BH1750 sensor. Note that you need to call Wire.begin(), even when using the default I2C pins. However, if you want to use different pins for SDA and SCL, you can use Wire.begin() to set them.

In the loop function, every second, we right the light level from the BH1750 in lux and print the value to the Serial Monitor. If you open your Serial Plotter and expose the sensor to a light source, you should see a bump in the plot:

Serial Plotter showing light response of BH1750
Serial Plotter showing light response of BH1750

Adding an OLED

Instead of displaying the data on the Serial Monitor it would be nicer to show them on a separate display. This would allow us to build a portable Lux Meter. In this section, we therefore add an OLED to the circuit and display the light intensity on it.

Connecting OLED to Arduino

Since the OLED is also an I2C device, connecting it is straightforward. We simply connect SDA and SCL to the same pins the BH1750 sensor is connected to. Since the OLED runs on 3.3V, we can also share the power supply lines. The picture below shows the complete wiring.

Connecting OLED and BH1750 with Arduino
Connecting OLED and BH1750 with Arduino

If you have any difficulties with the OLED, have a look at the tutorial How to Interface the SSD1306 I2C OLED Graphic Display With Arduino. The picture below shows the complete wiring on a real breadboard

Wiring of OLED and BH1750 with Arduino
Wiring of OLED and BH1750 with Arduino

Code to display BH1750 data on OLED

In this section, you will learn how to display the light intensity measured by the BH1750 on an OLED screen. To write to the OLED we will use the Adafruit_SSD1306 library. You can install it via the Library Manager as usual:

Adafruit_SSD1306 library installed in Library Manager
Adafruit_SSD1306 library installed in Library Manager

The code below read the light measurement from the BH1750 sensor and display the value in lux on the OLED. Have a look at the complete code first before we discuss its details.

#include "BH1750.h"
#include "Adafruit_SSD1306.h"

BH1750 luxMeter;
Adafruit_SSD1306 oled(128, 64, &Wire, -1);

void oled_init() {
  oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  oled.clearDisplay();
  oled.setTextSize(3);
  oled.setTextColor(WHITE);
}

void centered(const char* text, int y) {
  int16_t x1, y1;
  uint16_t w, h;
  oled.getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
  oled.setCursor(64 - w / 2, y);
  oled.print(text);
}

void display_lux() {
  static char text[30];
  float lux = luxMeter.readLightLevel();

  oled.clearDisplay();
  sprintf(text, "%.0f", lux);
  centered(text, 25);
  oled.display();
}

void setup() {
  oled_init();
  Wire.begin();
  luxMeter.begin();
}

void loop() {
  display_lux();
  delay(1000);
}

Libraries and Display Initialization

We start by including the necessary libraries for the BH1750 sensor and the Adafruit SSD1306 OLED display. We then initialize the OLED display in the oled_init() function. This function sets up the display, clears it, sets the text size, and color for the text.

#include "BH1750.h"
#include "Adafruit_SSD1306.h"

BH1750 luxMeter;
Adafruit_SSD1306 oled(128, 64, &Wire, -1);

void oled_init() {
  oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  oled.clearDisplay();
  oled.setTextSize(3);
  oled.setTextColor(WHITE);
}

Note that the I2C address for the OLED display is set to 0x3C in oled.begin(). Most of these small OLEDs use this address but yours might be different. If you don’t see anything on the OLED, it most likely has a different I2C address and you have change the address passed on to oled.begin(). If you don’t know the I2C address have a look at the How to Interface the SSD1306 I2C OLED Graphic Display With Arduino tutorial.

Display Functions

The centered() function is used to print text centered on the OLED display at a specified y-coordinate. The display_lux() function reads the light intensity in lux from the sensor and displays it on the OLED screen.

void centered(const char* text, int y) {
  // Function to center text on OLED display
}

void display_lux() {
  // Function to display light intensity on OLED display
}

Setup Function

In the setup() function, we initialize the serial communication for debugging purposes, initialize the OLED display, and begin communication with the BH1750 sensor. If you change the I2C pins the sensor is connected to, then Wire.begin() is the place you have to adjust.

void setup() {
  oled_init();
  Wire.begin();
  luxMeter.begin();
}

Loop Function

The loop() function continuously calls the display_lux() function to update and display value on the OLED screen. It then adds a delay of 1 second before the next update.

void loop() {
  display_lux();
  delay(1000);
}

Output on OLED

If you upload and run the code, you should see the light intensity in lux displayed on the OLED.

BH1750 Output on OLED
BH1750 Output on OLED

And there you have a nice lux meter you can use to measure light intensities!

Conclusions

In this tutorial you learned how to use the Ambient Light Sensor BH1750, an OLED and an Arduino Uno to build a lux meter.

Since the BH1750 has a low power mode and runs on 3.3V it would be especially suitable for building a battery-powered, portable lux meter using an ESP32. Have a look at the at the Simple ESP32 Internet Weather Station, where we use a battery-powered ESP32, for technical details.

Furthermore, if you use the lux meter mostly outside, I would recommend an e-Paper display instead of an OLED, since it will be much better to read in direct sunlight. The Weather Station on e-Paper Display tutorial, might come in handy here.

Finally, if you specifically want to measure UV light, we have a tutorial on that as well: UV Index Meter With VEML6070 and Arduino

If you have any questions, feel free to ask.

Happy tinkering ; )