BH1750 light sensor

The ROHM BH1750FVI on the GY-302 module: ambient light in lux over I2C, at address 0x23, or 0x5C with ADDR high. Aliases: GY-302, BH1750FVI, lux sensor.

It is the light sensor in the IoT and Pico kits. A light-dependent resistor gives a number that depends on the cell and the resistor beside it; the BH1750 gives lux. Its photodiode is filtered to the eye's response and its count is the light times 1.2, with nothing for the sketch to calibrate.

Pins

Pin What it does
VCC Supply, 3 V to 5 V. The module has a 3.3 V regulator for the chip.
GND Ground.
SCL I2C clock. The module carries the pull-ups.
SDA I2C data.
ADDR Low or open: 0x23. High: 0x5C, for a second sensor on the same bus.

The light

The slider over the sensor is the light falling on it, from 0 to 100 000 lux. It is logarithmic, because light is: a dark room is a few lux, a classroom a few hundred, an overcast day outdoors a few thousand and direct sun around a hundred thousand.

How it talks

There are no registers to read. Each write is a one-byte command, and each read is the two bytes of the last finished measurement, high byte first:

Command What it does
0x00 Power down.
0x01 Power on.
0x07 Reset: clears the reading. Only while powered on.
0x10, 0x11, 0x13 Measure continuously: high resolution (1 lx), high resolution 2 (0.5 lx), low resolution (4 lx).
0x20, 0x21, 0x23 The same, once; then the chip powers itself down.
0x40 to 0x47, 0x60 to 0x7F The high three and low five bits of MTreg, the measurement time.
  • The count is lux x 1.2 in high resolution, twice that in high resolution 2, and at most 65535. So lux = count / 1.2, and a sensor in full sun reads a flat 54612 lx.
  • A measurement takes 120 ms in the high-resolution modes and 16 ms in low resolution. Until the first one finishes the reading is 0.
  • MTreg is 69 at power on and 31 to 254 allowed. Both the time and the count scale with it, so a larger MTreg sees further into the dark and saturates sooner.
  • At power on the chip is powered down and waits for a command.

The library

BH1750.h (Christopher Laws' library, the one the Library Manager finds first) works as its tutorial uses it:

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

BH1750 lightMeter;

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

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

begin() takes a mode (BH1750::ONE_TIME_HIGH_RES_MODE and the others) and an address, setMTreg() changes the measurement time, and measurementReady() says whether the mode's time has passed. readLightLevel() returns -1 before begin() and -2 when the sensor does not answer.

The reading is a float built from whole hundredths, so printing it works on every board. Sums on it link only on the Uno R4; for arithmetic, lightMeter.readLightLevelCentis() returns the same reading in hundredths of a lux.

What the model gets right

From the ROHM BH1750FVI datasheet (Rev.D): the address and its pin, every command, the three resolutions, one-time and continuous modes with the power down after a one-time measurement, the reset that works only while powered on, the typical measurement times, MTreg and its effect on both time and count, and the saturation at 65535.

What it does not model

The spread of the 1.2 ratio between parts (0.96 to 1.44 in the sheet), the spectral response and light-source dependence (a slider's lux is the eye's lux), and the sheet's maximum measurement times (180 ms and 24 ms), which the library waits for. How the chip drops the low bits in low resolution is not in the sheet; the model rounds down to a multiple of 4.

Common mistakes

Reading before the first measurement has finished. The reading is 0 until then.

A one-time mode read twice. The chip powered down after the first measurement and the second read is the same number; the library sends the command again for you.

Two sensors on one bus with ADDR the same on both. Tie one high.

See it in action

Lux night lamp fades an LED up as the room goes dark, with the reading in lux on the serial monitor. Open it at /templates.