Skip to content

rpi-gpio

tested on simulator

Tier Tier 1
Protocol Raspberry Pi GPIO through gpiozero (lgpio, RPi.GPIO, pigpio)
Covers relays and relay boards, LEDs, buttons, reed switches and limit switches, PWM fans and dimmers, hobby servos
Hazard default low
Conformance control
Tested with gpiozero's mock pin factory

Estimated reach. Every Raspberry Pi with a 40-pin header, and thousands of add-on parts. Every Raspberry Pi since the 2014 B+ has the same 40-pin header with 26 usable GPIO pins, and gpiozero supports all of them including the Pi 5 through lgpio. What hangs off the pins (relays, LEDs, switches, fans, servos) is described in the device file, so any part driven by a digital level, PWM or a servo pulse is covered. Parts that need I2C, SPI or one-wire need other drivers.

The rpi-gpio driver drives Raspberry Pi GPIO pins through gpiozero, with digital outputs for relays and LEDs, digital inputs for buttons and switches, PWM for fans and dimmers, and servo pulses. Pins are named in the device file and channels use those names. watch_stop_button turns a GPIO input into a physical stop button for the hub.

Supports

ChannelDeviceValue
read, booldigital input with pull-up, pull-down or nonetrue while active
write, booldigital outputon or off
write, number in percent or dimensionlessPWM outputduty cycle, 0 to 100 % or 0 to 1
write, number in an angle unit, map mode: servoservoangle

Writes read back gpiozero's state. A servo reads as no value until the first write, since the servo gets no pulse before then.

Setup

gpiozero uses lgpio, which comes with Raspberry Pi OS Bookworm or later.

uv tool install --compile-bytecode "halkit[rpi-gpio] @ git+https://github.com/sohan-bhat/OpenHAL"
sudo apt install -y python3-lgpio    # if the hub's virtual environment can't see it

Join the gpio group. Off a Pi, pin_factory: mock uses gpiozero's mock pins.

ParameterDefaultMeaning
pinsrequiredNames to BCM GPIO numbers, { relay: 17, door: 22 }. rpi-gpio: { relay: 17 } is shorthand
active_hightruefalse inverts outputs for relay boards that switch on low
pullupDefault input pull, up, down or none
bouncenoneDefault input debounce such as 50 ms
on_connectoffoff starts digital outputs inactive, keep leaves the pin level
pin_factoryautoauto, lgpio, rpigpio, pigpio, native or mock

Pins are BCM numbers 0 to 27, so GPIO 17 is header pin 11. Pins in pins that no channel uses are allowed, which is how a stop button pin is declared.

Channel maps

Without a map a channel uses the pin of the same name.

connect: { rpi-gpio: { heat_mat: 17, fan: 18, vent: 12, door_closed: 22 }, active_high: false }
read:
  door_closed: { type: bool }
write:
  heat_mat: { type: bool }
  fan: { unit: percent, min: 0, max: 100, map: { active_high: true, frequency: 25000 } }
  vent: { unit: degree, min: 0, max: 80, map: { mode: servo } }
KeyDefaultMeaning
pinthe channel's nameA name from pins or a BCM number
modefrom the channel typeservo for servos, otherwise number outputs are PWM
active_highthe parameterPer-pin inversion. Inputs use the setting only with pull: none
pull, bouncethe parametersPer-input pull and debounce
frequency100PWM frequency in Hz
min_angle, max_angle-90, 90Servo range in degrees
min_pulse_ms, max_pulse_ms, frame_ms1, 2, 20Servo pulse widths and frame

With a pull-up a button wired to ground reads true when pressed. With pull: none, active_high sets the active level. PWM limits must fit 0 to 100 % or 0 to 1, and servo limits min_angle to max_angle.

The stop button

from openhal.drivers.rpi_gpio import watch_stop_button

button = watch_stop_button(27, kernel_stop, loop=asyncio.get_running_loop())
...
button.close()

watch_stop_button(pin, on_press, *, pull_up=True, active_state=None, bounce_s=0.05, loop=None, pin_factory=None) calls on_press on each press of BCM pin, on loop when given, a coroutine function as a task, and otherwise on gpiozero's thread. The function never touches an output. RpiGpioDriver.stop_button_pin() returns an unused stop_button pin from pins for the hub to wire up. A GPIO stop button only sends a stop request, so keep a hardware e-stop.

Example

openhal/drivers/rpi_gpio/examples/greenhouse-vent.hal.yaml drives an active-low relay, a PWM fan and a vent servo, reads a door switch, declares a stop button pin, and has an interlock and a watchdog rule. spec/examples/rpi-relay.hal.yaml is a single relay.

Errors and health

  • Pins held by another program, a missing pin library or a non-Pi host raise DriverError on connect.
  • Channels without a pin, two channels on one pin, non-bool inputs and outputs that aren't bool or number fail at load.
  • health() reports disconnected if any pin was released.

Limitations

  • No analog inputs, since the Pi has no ADC. Use an ADC board through another driver.
  • No I2C, SPI or one-wire.
  • Software PWM jitters at high frequencies, so use GPIO 12, 13, 18 or 19 for hardware PWM.

Hazard default and safe state

Low, since a pin drives 3.3 V at a few milliamps. Set the hazard from what the relay or transistor drives. safe_state_support is file.

On close or hub exit, gpiozero releases the pins, which usually become inputs. An active-low relay board without an input pull-up can then switch on, so fit a pull resistor that makes a released pin mean off and note the resistor in safe_state_note.

Sources