Skip to content

ricardoquesada/bluepad32-circuitpython

Repository files navigation

Introduction

Build Status Discord

Logo

Enables gamepad support for CircuitPython. Requires a board with an AirLift (ESP32) module, like:

Supported gamepads

Supported gamepads

Supports, most if not all, modern Bluetooth gamepads like:

  • Sony family: DualSense (PS5), DualShock 4 (PS4), DualShock 3 (PS3)
  • Nintendo family: Switch gamepads, Switch JoyCons, Wii, Wii U
  • Xbox Wireless family: models 1708, 1914, adaptive
  • Steam controller
  • Stadia controller
  • Android gamepads
  • Window gamepads
  • 8BitDo controllers
  • and more

For a complete list, see: https://bluepad32.readthedocs.io/en/latest/supported_gamepads/

How does it work

As mentioned above, only boards with the AirLift (ESP32) co-processor are supported. This is because the project consists of two parts:

  • "Bluepad32 library for CircuitPython", runs on the main processor: "C"
  • "Bluepad32 firmware", runs on the AirLift co-processor: "B"

How does it work

The gamepad (A), using Bluetooth, connects to the AirLift co-processor (B).

And AirLift (B) sends the gamepad data to the main processor (C). In the case of the MatrixPortal M4, the main processor is the SAMD51. But it could be different on other boards.

So, in order to use the library you have to flash the "Bluepad32 firmware" on AirLift. This is a simple step that needs to be done just once, and can be undone at any time. Info about Bluepad32 firmware is available here:

Dependencies

This driver depends on:

Please ensure all dependencies are available on the CircuitPython filesystem. This is easily achieved by downloading the Adafruit library and driver bundle or individual libraries can be installed using circup.

Installing to a Connected CircuitPython Device with Circup

Make sure that you have circup installed in your Python environment. Install it with the following command if necessary:

pip3 install circup

With circup installed and your CircuitPython device connected use the following command to install:

circup install bluepad32

Or the following command to update an existing version:

circup update

Usage Example

import time
import board
import busio
from digitalio import DigitalInOut
from bluepad32.bluepad32 import Bluepad32

# Connected gamepad
gamepad = None

# Callback that will be called once a gamepad is connected
def on_connect(gp):
    global gamepad
    gamepad = gp

    print("on_connect: ", gp)
    # Change ligthbar to Green: Red, Green, Blue
    gp.set_lightbar_color((0x00, 0xFF, 0x00))


# Callback that will be called when a gamepad is disconnected
def on_disconnect(gp):
    global gamepad
    gamepad = None
    print("on_disconnect: ", gp)


# If you are using a board with pre-defined ESP32 Pins:

esp32_cs = DigitalInOut(board.ESP_CS)
esp32_ready = DigitalInOut(board.ESP_BUSY)
esp32_reset = DigitalInOut(board.ESP_RESET)

spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
bp32 = Bluepad32(spi, esp32_cs, esp32_ready, esp32_reset, debug=0)
bp32.setup_callbacks(on_connect, on_disconnect)

# For Arduino Nano RP2040 Connect, instead you should use:
#  board.CS1, board.SCK1, board.MOSI1, board.MISO1

# Should display "Bluepad32 for Airlift vXXX"
print("Firmware version:", bp32.firmware_version)

while True:
    # Fetches data from Bluepad32 firmware, triggers callbaks, and more.
    # Must be called once per frame.
    bp32.update()

    if gamepad is None:
        continue

    if gamepad.button_a:  # button A pressed ?
        # Change color to Blue
        gamepad.set_lightbar_color((0x00, 0x00, 0xFF))

    if gamepad.button_b:  # Button B pressed ?
        # Turn on all 4 player LEDs
        gamepad.set_player_leds(0x0f)

    if gamepad.button_x:  # Button X pressed ?
        force = 128  # 0-255
        duration = 10  # 0-255
        gamepad.set_rumble(force, duration)

    # Small delay, simulates a 30 FPS game
    time.sleep(0.032)

Contributing

Contributions are welcome! Please read our Code of Conduct before contributing to help this project stay welcoming.