Files
led-driver-8/docs/pattern-contract.md

1.9 KiB

Pattern Contract (Important)

Pattern classes are loaded dynamically by Presets._load_dynamic_patterns().

Patterns must follow this contract exactly.

Required class shape

  • File name is the pattern id (for example blink.py -> pattern name blink).
  • Module exports a class with:
    • __init__(self, driver) where driver is the Presets instance.
    • run(self, preset) that returns a generator.

Presets binds patterns like this:

  • pattern_class(self).run
  • then calls self.patterns[preset.p](preset) and stores that generator.
  • every frame, Presets.tick() does next(self.generator).

run() generator rules

  • run() must yield frequently (normally once per tick loop).
  • Do not block inside run():
    • no sleep() / sleep_ms() / long loops without yield.
    • no network or file I/O.
  • Use time checks (utime.ticks_ms() + utime.ticks_diff(...)) to schedule updates.
  • Keep pattern state inside local variables in run() (or object fields if needed).

Drawing and brightness

  • Use self.driver.apply_brightness(color, preset.b) for per-preset brightness.
  • Write pixels through self.driver.n[...] / self.driver.n.fill(...).
  • Flush frame with self.driver.n.write().
  • If a pattern needs to clear, use black (0, 0, 0).

Step semantics

  • self.driver.step is shared pattern state managed by Presets.select(...) and patterns.
  • Patterns that use step-based progression should update self.driver.step themselves.
  • select(..., step=...) may set an explicit starting step.

Error handling

  • Let unexpected errors raise inside the generator.
  • Presets.tick() catches exceptions, logs, and stops the active generator.
  • Pattern code should not swallow broad exceptions unless there is a clear recovery path.

Built-ins

  • off and on are built-in methods on Presets, not loaded from this folder.
  • __init__.py is ignored by dynamic loader.