Adding Hexpansion support

Each supported Hexpansion has a small Python class in app/hexpansion/. It declares the VID/PID for detection, the commands it can receive, and how to tell when a command has been carried out. Everything else is handled by the base class.

What a module needs

Extend HexpansionModule from app/hexpansion/base.py and define:

Attribute / methodWhat to do
VID, PID The vendor and product IDs from the Hexpansion's EEPROM. The base class uses these to detect that the hardware is plugged in and derives FRIENDLY_NAME automatically.
COMMAND_OPTIONS A list of every command this Hexpansion can be asked to perform.

And define at least one of:

Attribute / methodWhat to do
on_button_down(event) Called for every button event. When the event satisfies the current command, set self.last_status = CommandStatus.PASSED. Use when the relevant hardware fires button events.
check_command() Called on every poll (~1 s). If the current command has been satisfied, set self.last_status = CommandStatus.PASSED. Use when relevant hardware doesn't fire events.

The three modules that ship with the game - Tildagon2024, MegaDrive and GPS, in app/hexpansion/ - should be good references.

Minimal example

A Hexpansion with a single big red button:

from .base import HexpansionModule, CommandStatus


class BigRedButtonModule(HexpansionModule):
    VID, PID = 0x????, 0x????  # from your hexpansion's EEPROM manifest
    COMMAND_OPTIONS = ["press"]

    def on_button_down(self, event):
        button = getattr(event, "button", None)
        if button is None:
            return
        if button.group != "BigRedButton":
            return
        if self.current_command == "press":
            self.last_status = CommandStatus.PASSED

Because the button press sets self.last_status directly, nothing else needs overriding.

Register it

  1. Save your class as app/hexpansion/MyHexpansion.py.
  2. Add it to MODULE_TYPES in app/hexpansion/__init__.py:
from .MyHexpansion import MyHexpansionModule

MODULE_TYPES = [
    Tildagon2024Module,
    MegaDriveModule,
    GPSModule,
    MyHexpansionModule,  # add here
]
VID/PID must be in the lookup table. The table in app/hexpansion_names.py is generated from the hexpansion-firmwares repo - run scripts/generate_hexpansion_names.py to regenerate it if your Hexpansion is added to the repo. Otherwise, add your VID/PID manually to MANUAL_FRIENDLY_NAME_OVERRIDES in the script.

Test it on hardware

Copy the app to the badge and reset it:

pipx run mpremote cp -r app/* :/apps/spaceteam/ && pipx run mpremote reset

Then, with your Hexpansion plugged in, open the Race Condition app and select Test modules from the main menu and pick your hexpansion. It will step through each detected command for the hexpansion; perform the action and it advances automatically (hold Cancel for 2 s to skip). If your module doesn't appear it wasn't detected - check that its VID/PID is in app/hexpansion_names.py and regenerate with scripts/generate_hexpansion_names.py if needed.