Raspberry Pi Light Sensor

Measuring light level on a Raspberry Pi means working around the fact that GPIO pins are digital-only, using a light-dependent resistor (LDR) paired with a capacitor so gpiozero's LightSensor class can time how long the pin takes to charge.

The Problem: GPIO Pins Cannot Read a Varying Voltage

A light-dependent resistor is a genuinely analog component - its resistance is high in darkness and drops as more light falls on it - but a Raspberry Pi has no analog input pins at all. Every GPIO pin can only tell you whether the voltage on it is above or below a single threshold, so there is no pin you can just connect an LDR to and read a light level directly the way you could on a microcontroller with a built-in analog-to-digital converter.

The Workaround: Timing a Capacitor's Charge

The trick gpiozero's LightSensor relies on is to pair the LDR with a small capacitor and measure time instead of voltage. The pin briefly drives low to fully discharge the capacitor, then switches to being an input and the code starts a stopwatch. Current trickles in through the LDR and charges the capacitor; once the rising voltage crosses the pin's high threshold, the input reads as high and the stopwatch stops. A brightly lit LDR has low resistance, so the capacitor charges quickly and the timed interval is short; in darkness the LDR's resistance is high, charging is slow, and the interval is long. LightSensor repeats this many times a second and converts the interval into a 0.0 to 1.0 reading.

  • LDR wired from the 3.3V rail to a chosen GPIO pin.
  • A small capacitor, commonly in the 1 to 10 microfarad range, wired from that same GPIO pin to GND.
  • The two components share the single GPIO pin as their junction - no separate pins for 'in' and 'out'.

Example

from gpiozero import LightSensor
from time import sleep

ldr = LightSensor(18)

while True:
    print(f'Light level: {ldr.value:.2f}')  # 0.0 (dark) to 1.0 (bright)
    sleep(0.5)

Example

from gpiozero import LightSensor, LED
from signal import pause

ldr = LightSensor(18)
lamp = LED(17)

ldr.when_dark = lamp.on
ldr.when_light = lamp.off

pause()
Note: If you need an actual numeric light reading rather than a relative 0 to 1 value - for example lux-like measurements you can compare across projects - the more direct route is a real analog-to-digital converter chip such as the MCP3008, wired over SPI, which gpiozero also supports directly through its MCP3xxx family of classes.
ApproachWhat you getExtra parts
LDR + capacitor (RC timing)Relative brightness, 0.0 to 1.0Just one capacitor, no chips
ADC chip (e.g. MCP3008)An actual numeric analog readingA dedicated SPI ADC IC
Note: LightSensor's threshold argument (0.1 by default) controls the value where when_light and when_dark fire, and charge_time_limit caps how long it will wait for the capacitor before giving up and reporting fully dark - both are worth tuning if your particular LDR and capacitor combination reads consistently too bright or too dark.
Note: Component sizing matters more than it looks. Too small a capacitor charges almost instantly regardless of light level, giving you little useful range to measure; too large a capacitor charges so slowly that readings lag noticeably behind real changes in light. The values in gpiozero's own examples are a reasonable starting point, but your specific LDR may need some experimentation.

Exercise: Raspberry Pi Sensors

Why can't a Raspberry Pi directly read a simple analog sensor like an LDR light sensor on a GPIO pin?