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 W | BH1750 lux sensor (GY-302) | Wire | Notes |
|---|---|---|---|
| 3V3 | VCC | red | 3V3 is pin 36. |
| GND | GND | black | |
| GP5 | SCL | yellow | GP5 is physical pin 7 (I2C0 SCL). |
| GP4 | SDA | blue | GP4 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
# 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)# 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
BH1750 at 0x23
312.5 lx bright room / office
318.3 lx bright room / office
45.8 lx dim roomBH1750 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.