A simple interface to GPIO devices with Raspberry Pi
—
The pin factory system provides an abstracted interface for different GPIO backends, board information, and pin management. This enables GPIO Zero to work with multiple underlying GPIO libraries and provides comprehensive hardware abstraction.
Abstract base class for all pin factories.
class Factory:
def __init__(self):
"""
Abstract base class for pin factories.
"""
def close(self):
"""Close the factory and release all resources."""
def reset(self):
"""Reset the factory to its initial state."""
def pin(self, spec) -> 'Pin':
"""
Create a pin object for the specified pin.
Parameters:
- spec: Pin specification (int, str, or PinInfo)
Returns:
Pin object for the specified pin
"""
def spi(self, *, port=0, device=0) -> 'SPI':
"""
Create an SPI interface object.
Parameters:
- port: int - SPI port number
- device: int - SPI device (chip select) number
Returns:
SPI interface object
"""
def reserve_pins(self, requester, *pins):
"""Reserve pins for exclusive use by requester."""
def release_pins(self, requester, *pins):
"""Release pin reservations for requester."""
def release_all(self, requester):
"""Release all pin reservations for requester."""
@property
def board_info(self) -> 'BoardInfo':
"""Information about the current board."""
@property
def ticks(self) -> int:
"""Current system tick count."""
def ticks_diff(self, later: int, earlier: int) -> int:
"""Calculate difference between two tick counts."""Abstract base class representing a GPIO pin.
class Pin:
def __init__(self, factory, info):
"""
Abstract base class for GPIO pins.
Parameters:
- factory: Factory that created this pin
- info: PinInfo object describing this pin
"""
def close(self):
"""Close the pin and release resources."""
def output_with_state(self, state: bool):
"""Configure pin as output and set initial state."""
def input_with_pull(self, pull: str):
"""Configure pin as input with pull resistor."""
@property
def number(self) -> int:
"""Pin number."""
@property
def info(self) -> 'PinInfo':
"""Pin information object."""
@property
def factory(self) -> Factory:
"""Factory that created this pin."""
@property
def function(self) -> str:
"""Current pin function ('input', 'output', 'alt0', etc.)."""
@function.setter
def function(self, value: str): ...
@property
def state(self) -> bool:
"""Current pin state (True=HIGH, False=LOW)."""
@state.setter
def state(self, value: bool): ...
@property
def pull(self) -> str:
"""Current pull resistor setting ('up', 'down', 'floating')."""
@pull.setter
def pull(self, value: str): ...
@property
def bounce(self) -> float:
"""Bounce time in seconds for edge detection."""
@bounce.setter
def bounce(self, value: float): ...
@property
def edges(self) -> str:
"""Edge detection setting ('none', 'falling', 'rising', 'both')."""
@edges.setter
def edges(self, value: str): ...
@property
def frequency(self) -> float:
"""PWM frequency in Hz."""
@frequency.setter
def frequency(self, value: float): ...
@property
def when_changed(self) -> callable:
"""Callback function for pin state changes."""
@when_changed.setter
def when_changed(self, value: callable): ...Abstract base class for SPI interfaces.
class SPI:
def __init__(self, factory, port, device):
"""
Abstract base class for SPI interfaces.
Parameters:
- factory: Factory that created this interface
- port: SPI port number
- device: SPI device number
"""
def close(self):
"""Close the SPI interface."""
def transfer(self, data: list) -> list:
"""
Transfer data over SPI.
Parameters:
- data: List of bytes to send
Returns:
List of bytes received
"""
@property
def closed(self) -> bool:
"""Returns True if interface is closed."""
@property
def port(self) -> int:
"""SPI port number."""
@property
def device(self) -> int:
"""SPI device (chip select) number."""Information about a GPIO board.
class BoardInfo:
def __init__(self, headers, **kwargs):
"""
Information about a GPIO board.
Parameters:
- headers: Dictionary of HeaderInfo objects
- **kwargs: Additional board properties
"""
def find_pin(self, spec) -> list:
"""
Find pin by specification.
Parameters:
- spec: Pin specification (number, name, or pattern)
Returns:
List of (header, pin_info) tuples matching specification
"""
@property
def headers(self) -> dict:
"""Dictionary of headers on this board."""
@property
def pins(self) -> dict:
"""Dictionary of all pins on this board."""Information about a pin header.
class HeaderInfo:
def __init__(self, name, rows, columns, **kwargs):
"""
Information about a pin header.
Parameters:
- name: Header name
- rows: Number of rows
- columns: Number of columns
- **kwargs: Additional header properties
"""
@property
def name(self) -> str:
"""Header name."""
@property
def rows(self) -> int:
"""Number of rows in header."""
@property
def columns(self) -> int:
"""Number of columns in header."""
@property
def pins(self) -> dict:
"""Dictionary of pins in this header."""Information about a specific pin.
class PinInfo:
def __init__(self, number, name, **kwargs):
"""
Information about a specific pin.
Parameters:
- number: Pin number
- name: Pin name
- **kwargs: Additional pin properties
"""
@property
def number(self) -> int:
"""Pin number."""
@property
def name(self) -> str:
"""Pin name."""
@property
def function(self) -> str:
"""Default pin function."""
@property
def pull(self) -> str:
"""Default pull resistor setting."""
@property
def row(self) -> int:
"""Header row position."""
@property
def col(self) -> int:
"""Header column position."""Board information specific to Raspberry Pi.
class PiBoardInfo(BoardInfo):
def __init__(self, revision=None, **kwargs):
"""
Raspberry Pi board information.
Parameters:
- revision: Pi revision string or None for auto-detect
- **kwargs: Additional board properties
"""
@property
def revision(self) -> str:
"""Pi board revision string."""
@property
def model(self) -> str:
"""Pi model name."""
@property
def pcb_revision(self) -> str:
"""PCB revision."""
@property
def memory(self) -> int:
"""Memory size in MB."""
@property
def manufacturer(self) -> str:
"""Board manufacturer."""
@property
def storage(self) -> str:
"""Storage type."""
@property
def usb(self) -> int:
"""Number of USB ports."""
@property
def ethernet(self) -> int:
"""Number of Ethernet ports."""
@property
def wifi(self) -> bool:
"""True if WiFi is available."""
@property
def bluetooth(self) -> bool:
"""True if Bluetooth is available."""
@property
def csi(self) -> int:
"""Number of CSI camera connectors."""
@property
def dsi(self) -> int:
"""Number of DSI display connectors."""def pi_info(revision=None) -> PiBoardInfo:
"""
Return board information for current or specified Pi revision.
Parameters:
- revision: str or None - Pi revision string or None for current Pi
Returns:
PiBoardInfo object for the specified Pi
"""# Global pin factory configuration
from gpiozero import Device
from gpiozero.pins.pigpio import PiGPIOFactory
Device.pin_factory = PiGPIOFactory()# Individual device pin factory
from gpiozero import LED
from gpiozero.pins.native import NativeFactory
led = LED(17, pin_factory=NativeFactory())GPIO Zero includes several pin factory implementations:
The default factory automatically selects the best available backend:
from gpiozero.pins.native import NativeFactory
Device.pin_factory = NativeFactory()Pure Python implementation, works on any Pi but limited functionality.
from gpiozero.pins.rpigpio import RPiGPIOFactory
Device.pin_factory = RPiGPIOFactory()Uses RPi.GPIO library, good compatibility but limited PWM.
from gpiozero.pins.pigpio import PiGPIOFactory
Device.pin_factory = PiGPIOFactory()High-performance library with accurate timing and hardware PWM.
from gpiozero.pins.lgpio import LGPIOFactory
Device.pin_factory = LGPIOFactory()Modern replacement for pigpio with similar features.
For testing and development without hardware:
from gpiozero.pins.mock import MockFactory
Device.pin_factory = MockFactory()from gpiozero import Device
# Get current board info
board = Device.pin_factory.board_info
print(f"Board: {board.model}")
print(f"Revision: {board.revision}")
print(f"Memory: {board.memory}MB")
# Find pins by name
gpio17_pins = board.find_pin("GPIO17")
for header, pin_info in gpio17_pins:
print(f"Pin {pin_info.number}: {pin_info.name}")
# List all pins
for pin_num, pin_info in board.pins.items():
print(f"Pin {pin_num}: {pin_info.name}")from gpiozero import LED, Device
from gpiozero.pins.pigpio import PiGPIOFactory
from gpiozero.pins.rpigpio import RPiGPIOFactory
# Set global pin factory
Device.pin_factory = PiGPIOFactory()
# All devices now use pigpio
led1 = LED(17)
led2 = LED(18)
# Override for specific device
led3 = LED(19, pin_factory=RPiGPIOFactory())from gpiozero import LED
from gpiozero.pins.pigpio import PiGPIOFactory
# Connect to remote Pi
remote_factory = PiGPIOFactory(host='192.168.1.100', port=8888)
led = LED(17, pin_factory=remote_factory)
led.on()from gpiozero import LED, Button
from gpiozero.pins.mock import MockFactory, MockPWMPin
# Set up mock factory
mock_factory = MockFactory()
Device.pin_factory = mock_factory
# Create devices (no hardware needed)
led = LED(17)
button = Button(2)
# Simulate hardware
mock_factory.pin(17).drive_high() # Simulate LED on
mock_factory.pin(2).drive_low() # Simulate button press
# Check device states
print(f"LED is {'on' if led.is_lit else 'off'}")
print(f"Button is {'pressed' if button.is_pressed else 'released'}")from gpiozero.pins import Factory, Pin
from gpiozero import Device
class MyCustomFactory(Factory):
def __init__(self):
super().__init__()
# Initialize custom hardware interface
def pin(self, spec):
# Return custom pin implementation
return MyCustomPin(self, spec)
def _get_board_info(self):
# Return custom board information
return my_board_info
# Use custom factory
Device.pin_factory = MyCustomFactory()from gpiozero import LED, Device
# Create device (pins are automatically reserved)
led = LED(17)
# Manual pin reservation
factory = Device.pin_factory
factory.reserve_pins(led, 17, 18, 19)
# Check reservations
try:
led2 = LED(17) # This will fail - pin already reserved
except GPIOPinInUse:
print("Pin 17 is already in use")
# Release reservations
led.close() # Automatically releases pin 17
factory.release_pins(led, 18, 19) # Manual releasefrom gpiozero import MCP3008
# Default SPI (port=0, device=0)
adc = MCP3008(channel=0)
# Custom SPI configuration
adc2 = MCP3008(channel=0, port=0, device=1) # Use CE1 instead of CE0
# Access underlying SPI interface
spi = Device.pin_factory.spi(port=0, device=0)
response = spi.transfer([0x01, 0x80, 0x00]) # Raw SPI transfer
spi.close()Install with Tessl CLI
npx tessl i tessl/pypi-gpiozero