refactor(led-driver): simplify websocket runtime and test layout
This commit is contained in:
51
docs/pattern-contract.md
Normal file
51
docs/pattern-contract.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user