Preview build — page text is a draft awaiting human review. Code badges come from real compiles. The flasher is real but not yet hardware-tested; the Playground is still a preview.

BH1750 light sensor with Raspberry Pi Pico W — lux in MicroPython

Measure light in lux with a BH1750 (GY-302) on Pico W I2C0 (GP4/GP5) in MicroPython: two I2C commands and a two-byte read, no library.

MicroPythonVerified — micropython (mpy-cross v1.29.0), 3 Nov 2026Compile-only

Community draft — report a mistake

The BH1750 is a digital light meter: it reports lux directly over I2C. On the Pico W that takes two commands — power on, continuous high-resolution mode — and then a two-byte read divided by 1.2.

Wire it to 3V3 and I2C0 (GP4/GP5). The script prints lux once a second with a rough description of what that light level means.

Wiring

Raspberry Pi Pico WOnly the pins used are shown · 3.3 V logicBH1750 lux sensor (GY-302)GNDGP4GP53V3VCCGNDSCLSDAADDR (not connected)
Every connection
Raspberry Pi Pico WBH1750 lux sensor (GY-302)WireNotes
3V3VCCred3V3 is pin 36.
GNDGNDblack
GP5SCLyellowGP5 is physical pin 7 (I2C0 SCL).
GP4SDAblueGP4 is physical pin 6 (I2C0 SDA). ADDR left open = 0x23.

3–5 V (on-board regulator) part, 3.3 V board. The GY-302 has a 3.3 V regulator and accepts 3–5 V on VCC; its pull-ups suit both 3.3 V and 5 V boards.

Board quirks

  • Unlike an LDR, the BH1750 gives calibrated lux, so readings compare between sensors — useful for grow lights and auto-brightness.
  • The sensor needs up to 180 ms per high-resolution reading; reading faster just returns the previous value.
  • It saturates at about 54,000 lx. Indian midday sun can reach 100,000 lx, so outdoors it will clip unless you shade it or change the measurement time register.

Code

main.pyMicroPython
# BH1750 (GY-302) light sensor in lux on a Raspberry Pi Pico W (MicroPython, no library).
# Wiring: VCC -> 3V3 (pin 36), GND -> GND, SCL -> GP5 (pin 7), SDA -> GP4 (pin 6). I2C0.
# ADDR unconnected/LOW = 0x23, HIGH = 0x5C.
from machine import Pin, I2C
import time

i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=400_000)
found = i2c.scan()
addr = 0x23 if 0x23 in found else (0x5C if 0x5C in found else None)
if addr is None:
    raise SystemExit("No BH1750 at 0x23/0x5C - found {}".format([hex(a) for a in found]))

i2c.writeto(addr, b"\x01")  # power on
i2c.writeto(addr, b"\x10")  # continuous high-resolution mode (1 lx steps, up to 180 ms per reading)
time.sleep_ms(180)
print("BH1750 at", hex(addr))


def lux():
    hi, lo = i2c.readfrom(addr, 2)
    return ((hi << 8) | lo) / 1.2  # datasheet: count / 1.2 = lux


def describe(lx):
    if lx < 10:
        return "dark"
    if lx < 200:
        return "dim room"
    if lx < 1000:
        return "bright room / office"
    if lx < 10000:
        return "daylight, shade"
    return "direct sun"


while True:
    lx = lux()
    print("{:8.1f} lx  {}".format(lx, describe(lx)))
    time.sleep(1)

Expected serial output

REPL / Thonny shellOutput
BH1750 at 0x23
   312.5 lx  bright room / office
   318.3 lx  bright room / office
    45.8 lx  dim room

Common errors

No BH1750 at 0x23/0x5C

Check SDA/SCL (GP4 is pin 6, GP5 is pin 7) and 3V3. If ADDR is wired HIGH, the script finds 0x5C on its own.

Always 0.0 lx

The power-on or mode command did not arrive. Re-run; if it persists, the module is faulty.

↑↓ to move · Enter to open