rpi-controls - RPi’s GPIO buttons

The rpicontrols package simplifies interactions with physical buttons connected to GPIO pins on a Raspberry Pi.

It abstracts away the complexity of monitoring the state of GPIO pins to detect events such as presses, clicks, double clicks… User code can subscribe to those high-level events the same way it would with most UI frameworks.

from rpicontrols import Controller, Button, PullType, make_controller

# Initialize the button controller. A single instance can handle as many buttons as needed.
controller: Controller = make_controller()

# Create the button, connected to pin 22.
button: Button = controller.make_button(
    input_pin_id=22,  # Id of the GPIO pin the button switch is connected to.
    input=Button.InputType.PRESSED_WHEN_OFF,  # Depends on the physical wiring of the button.
    pull=PullType.UP  # Whether to enable pull-up or pull-down resistor. Use PullType.NONE to disable.
)

# Define a callback to run when button is clicked.
async def on_click_callback(button: Button) -> None:
    print(f'Button {button.name} clicked!')

    # Run some IO-bound task without blocking.
    # Other event handlers may run while waiting.
    await asyncio.sleep(2)

# Subscribe to the click event.
button.add_on_click(on_click_callback)

# Start controller main loop. Use controller.start_in_thread() for the non-blocking version.
controller.run()

As shown in the example above, event handlers can be either synchronous or asynchronous functions.

Synchronous handlers can only run one at a time. One handler must finish its execution for another to be executed, so long-running synchronous handlers are discouraged.

On the contrary, asynchronous handlers can run concurrently, in the sense that one handler can run while another is awaiting an IO-bound task.

In all cases, event handlers are all run on the same thread.

Summary

make_controller([gpio_driver])

Creates a new instance of a button controller.

Controller(driver)

Represents the object managing all buttons.

Controller.Status(value)

Defines the various steps in a controller lifecycle.

Button(input_pin_id, input_type[, name])

Represents a button connected to the GPIO.

Functions

rpicontrols.make_controller(gpio_driver=None)

Creates a new instance of a button controller. One instance of a controller is required to work with any number of buttons, so a call to this function is mandatory when initializing the client code.

Parameters

gpio_driver (Optional[rpicontrols.gpio_driver.GpioDriver]) – object abstracting access to the GPIO, defaults to None in which case an implementation based on RPi.GPIO will be used (see rpicontrols.rpi_gpio_driver.RpiGpioDriver). This parameter is unlikely to require a different value in a production context. It is mostly here to help mocking the GPIO access when testing.

Return type

A new controller, accepting button declaration and ready to be started.

Controller Object

class rpicontrols.Controller(driver)

Represents the object managing all buttons. It monitors the state of the GPIO and calls event callbacks on buttons when appropriate.

Parameters

driver (gpio_driver.GpioDriver) –

class Status(value)

Defines the various steps in a controller lifecycle.

READY = 'ready'

Controller is waiting for being started, either with Controller.run() or Controller.start_in_thread()

RUNNING = 'running'

Controller has been started and is monitoring GPIO. This is the active state of the controller, during which button events can be raised.

STOPPED = 'stopped'

Controller is at full stop and all event callbacks have returned. Controller cannot be started again.

STOPPING = 'stopping'

Controller is being shut down. No new events will be raised at this point because GPIO is no longer monitored, but ongoing callbacks may still need to finish.

property buttons: Iterable[rpicontrols.controller.Button]

Gets the collection of buttons that have been registered using make_button().

delete_button(button)

Removes the button from the controller. The controller will stop monitoring this button events and will not update its status anymore. Call this method to save resources if this button is not useful anymore. It is not required to delete all buttons before deleting this controller.

Parameters

button (rpicontrols.controller.Button) –

Return type

None

make_button(input_pin_id, input, pull, name=None, bounce_time=0)

Creates a new button connected to pins of the GPIO.

Parameters
  • input_pin_id (int) – id of the input pin the button is connected to. Its meaning depends on the selected GPIO driver. The default driver is rpicontrols.rpi_gpio_driver.RpiGpioDriver which uses RPi.GPIO.BOARD unless otherwise specified.

  • input (rpicontrols.controller.Button.InputType) – value describing the button physical behavior with respect to the electrical wiring. It helps the controller tell when the button is considered pressed or released, depending on the state of the GPIO.

  • pull (rpicontrols.gpio_driver.PullType) – whether built-in pull-up or pull-down should be used for this button. Those are resistors integrated in the Raspberry Pi’s circuits that can be used to make sure GPIO pins are always at a predictable potential. The appropriate value is dependent on how the physical button or switch has been wired to the GPIO. See Wikipedia for more information.

  • name (Optional[str]) – optional name, used for documentation and logging purposes. If unset, a default unique name will be assigned.

  • bounce_time (int) – timespan after a GPIO rising or falling edge during which new edges should be ignored. This is meant to avoid unwanted edge detections due to the transient instability of switches when they change state. The appropriate value depends on the actual physical switch or button in use.

Return type

rpicontrols.controller.Button

run()

Runs the engine controlling the GPIO.

This method blocks until the controller is stopped. See also start_in_thread() for a non-blocking version of this start method.

Return type

None

start_in_thread()

Runs the engine controlling the GPIO in its own thread.

Return type

None

property status: rpicontrols.controller.Controller.Status

Gets the current status of this controller.

stop(wait=False)

Stops this controller.

Attempting to stop a controller that is already stopped does nothing. Otherwise, calling this method on a controller that is in a status different from Controller.Status.RUNNING raises an exception.

Parameters

wait (bool) – whether to block until the controller has actually stopped. If False, the method returns quicker but there is no guarantee that the controller has actually reached the Status.STOPPED status.

Return type

None

stop_on_signals(signals=[<Signals.SIGINT: 2>, <Signals.SIGTERM: 15>])

Registers a handler to stop this controller when specific signals are caught.

Parameters

signals (Iterable[signal.Signals]) – list of signals that should stop this controller.

Button Objects

class rpicontrols.Button(input_pin_id, input_type, name=None)

Represents a button connected to the GPIO.

This object holds the current state of the button and the event handlers to be called when events are raised.

Parameters
  • input_pin_id (int) –

  • input_type (Button.InputType) –

  • name (Optional[str]) –

AsyncEventHandler

Represents the type for asynchronous event handlers.

alias of Callable[[Button], Coroutine[Any, Any, Any]]

EventHandler

Represents the type for all kinds of event handlers (synchronous or asynchronous).

alias of Union[Callable[[Button], None], Callable[[Button], Coroutine[Any, Any, Any]]]

EventHandlerList

Represents the type for lists of event handlers (synchronous or asynchronous).

alias of List[Union[Callable[[Button], None], Callable[[Button], Coroutine[Any, Any, Any]]]]

class InputType(value)

Defines the various physical behaviors of a button with respect to the wiring of its corresponding GPIO pins.

PRESSED_WHEN_OFF = 2

The button is detected as pressed when its GPIO input pin is off.

PRESSED_WHEN_ON = 1

The button is detected as pressed when its GPIO input pin is on.

SyncEventHandler

Represents the type for synchronous event handlers.

alias of Callable[[Button], None]

add_on_click(func)

Adds a handler of the click event. This handler will be called whenever the button is pressed and released once. If a second click happens before double_click_timeout expires, this event is not raised. The double click event is raised instead.

Parameters

func (EventHandler) –

Return type

None

add_on_double_click(func)

Adds a handler of the double click event. This handler will be called whenever the button is pressed and released twice within a period of time at most equal to double_click_timeout.

Parameters

func (EventHandler) –

Return type

None

add_on_long_press(func)

Adds a handler of the long press event. This handler will be called whenever the button has been kept in its pressed state for a period of time equal to long_press_timeout seconds.

Parameters

func (EventHandler) –

Return type

None

add_on_press(func)

Adds a handler of the press event. This handler will be called whenever the button is pressed.

Parameters

func (EventHandler) –

Return type

None

add_on_release(func)

Adds a handler of the release event. This handler will be called whenever the button is released after having been pressed.

Parameters

func (EventHandler) –

Return type

None

double_click_timeout: float

Period of time in seconds that defines the double click speed. For a double click to be detected, two clicks must occur so that the number of elapsed seconds between the first press and the second release is at most equal to this timeout. This timeout has an indirect impact on the detection of the click events: since no click event is raised when a double click occurs, the controller must wait for this double click timeout to expire once a first click has been detected before the actual click event can be raised.

property input_type: InputType

Returns a value indicating the physical status of the button with respect to GPIO status.

long_press_timeout: float

Number of consecutive seconds the button must be pressed for the long pressed event to be raised.

property long_pressed: bool

Returns a value indicating whether the button is currently pressed and has been so for least a period of time at least equal to long_press_timeout.

property name: str

Informational name of this button. This name is used mainly for logging purposes.

property pin_id: int

Id of the input pin the button is connected to. See Controller.make_button() for more info on its meaning.

property pressed: bool

Returns a value indicating whether the button is currently pressed.

remove_on_click(func)

Removes a handler of the click event.

Parameters

func (EventHandler) –

Return type

None

remove_on_double_click(func)

Removes a handler of the double click event.

Parameters

func (EventHandler) –

Return type

None

remove_on_long_press(func)

Removes a handler of the long press event.

Parameters

func (EventHandler) –

Return type

None

remove_on_press(func)

Removes a handler of the press event.

Parameters

func (EventHandler) –

Return type

None

remove_on_release(func)

Removes a handler of the release event.

Parameters

func (EventHandler) –

Return type

None

GPIO Drivers

class rpicontrols.rpi_gpio_driver.RpiGpioDriver(mode: int = RPi.GPIO.BOARD)

Implementation of the GPIO driver interface based on RPi.GPIO. This is the default driver for button controllers.

Parameters

mode – value describing the meaning of GPIO pin numbers. Refer to RPi.GPIO documentation for more information.