--- name: mainline-sensors description: Sensor framework for real-time input in Mainline compatibility: opencode metadata: audience: developers source_type: codebase --- ## What This Skill Covers This skill covers Mainline's sensor framework - how to use, create, and integrate sensors for real-time input. ## Key Concepts ### Sensor Base Class (engine/sensors/__init__.py) ```python class Sensor(ABC): name: str unit: str = "" @property def available(self) -> bool: """Whether sensor is currently available""" return True @abstractmethod def read(self) -> SensorValue | None: """Read current sensor value""" ... def start(self) -> None: """Initialize sensor (optional)""" pass def stop(self) -> None: """Clean up sensor (optional)""" pass ``` ### SensorValue Dataclass ```python @dataclass class SensorValue: sensor_name: str value: float timestamp: float unit: str = "" ``` ### SensorRegistry Discovers and manages sensors globally: ```python from engine.sensors import SensorRegistry registry = SensorRegistry() sensor = registry.get("mic") ``` ### SensorStage Pipeline adapter that provides sensor values to effects: ```python from engine.pipeline.adapters import SensorStage stage = SensorStage(sensor_name="mic") ``` ## Built-in Sensors | Sensor | File | Description | |--------|------|-------------| | MicSensor | sensors/mic.py | Microphone input (RMS dB) | | OscillatorSensor | sensors/oscillator.py | Test sine wave generator | | PipelineMetricsSensor | sensors/pipeline_metrics.py | FPS, frame time, etc. | ## Param Bindings Effects declare sensor-to-param mappings: ```python class GlitchEffect(EffectPlugin): param_bindings = { "intensity": {"sensor": "mic", "transform": "linear"}, } ``` ### Transform Functions - `linear` - Direct mapping to param range - `exponential` - Exponential scaling - `threshold` - Binary on/off ## Adding a New Sensor 1. Create `engine/sensors/my_sensor.py` 2. Inherit from `Sensor` ABC 3. Implement required methods 4. Register in `SensorRegistry` Example: ```python class MySensor(Sensor): name = "my-sensor" unit = "units" def read(self) -> SensorValue | None: return SensorValue( sensor_name=self.name, value=self._read_hardware(), timestamp=time.time(), unit=self.unit ) ``` ## Using Sensors in Effects Access sensor values via EffectContext: ```python def process(self, buf, ctx): mic_level = ctx.get_sensor_value("mic") if mic_level and mic_level > 0.5: # Apply intense effect ... ``` Or via param_bindings (automatic): ```python # If intensity is bound to "mic", it's automatically # available in self.config.intensity ```