"""Value source schemas (CRUD).""" from datetime import datetime from typing import List, Literal, Optional from pydantic import BaseModel, Field class ValueSourceCreate(BaseModel): """Request to create a value source.""" name: str = Field(description="Source name", min_length=1, max_length=100) source_type: Literal["static", "animated", "audio", "adaptive_time", "adaptive_scene", "daylight"] = Field(description="Source type") # static fields value: Optional[float] = Field(None, description="Constant value (0.0-1.0)", ge=0.0, le=1.0) # animated fields waveform: Optional[str] = Field(None, description="Waveform: sine|triangle|square|sawtooth") speed: Optional[float] = Field(None, description="Speed: animated=cpm (0.1-120), daylight=multiplier (0.1-10)", ge=0.1, le=120.0) min_value: Optional[float] = Field(None, description="Minimum output (0.0-1.0)", ge=0.0, le=1.0) max_value: Optional[float] = Field(None, description="Maximum output (0.0-1.0)", ge=0.0, le=1.0) # audio fields audio_source_id: Optional[str] = Field(None, description="Mono audio source ID") mode: Optional[str] = Field(None, description="Audio mode: rms|peak|beat") sensitivity: Optional[float] = Field(None, description="Gain multiplier (0.1-20.0)", ge=0.1, le=20.0) smoothing: Optional[float] = Field(None, description="Temporal smoothing (0.0-1.0)", ge=0.0, le=1.0) auto_gain: Optional[bool] = Field(None, description="Auto-normalize audio levels to full range") # adaptive fields schedule: Optional[list] = Field(None, description="Time-of-day schedule: [{time: 'HH:MM', value: 0.0-1.0}]") picture_source_id: Optional[str] = Field(None, description="Picture source ID for scene mode") scene_behavior: Optional[str] = Field(None, description="Scene behavior: complement|match") # daylight fields use_real_time: Optional[bool] = Field(None, description="Use wall-clock time instead of simulation") latitude: Optional[float] = Field(None, description="Geographic latitude (-90 to 90)", ge=-90.0, le=90.0) description: Optional[str] = Field(None, description="Optional description", max_length=500) tags: List[str] = Field(default_factory=list, description="User-defined tags") class ValueSourceUpdate(BaseModel): """Request to update a value source.""" name: Optional[str] = Field(None, description="Source name", min_length=1, max_length=100) # static fields value: Optional[float] = Field(None, description="Constant value (0.0-1.0)", ge=0.0, le=1.0) # animated fields waveform: Optional[str] = Field(None, description="Waveform: sine|triangle|square|sawtooth") speed: Optional[float] = Field(None, description="Speed: animated=cpm (0.1-120), daylight=multiplier (0.1-10)", ge=0.1, le=120.0) min_value: Optional[float] = Field(None, description="Minimum output (0.0-1.0)", ge=0.0, le=1.0) max_value: Optional[float] = Field(None, description="Maximum output (0.0-1.0)", ge=0.0, le=1.0) # audio fields audio_source_id: Optional[str] = Field(None, description="Mono audio source ID") mode: Optional[str] = Field(None, description="Audio mode: rms|peak|beat") sensitivity: Optional[float] = Field(None, description="Gain multiplier (0.1-20.0)", ge=0.1, le=20.0) smoothing: Optional[float] = Field(None, description="Temporal smoothing (0.0-1.0)", ge=0.0, le=1.0) auto_gain: Optional[bool] = Field(None, description="Auto-normalize audio levels to full range") # adaptive fields schedule: Optional[list] = Field(None, description="Time-of-day schedule") picture_source_id: Optional[str] = Field(None, description="Picture source ID for scene mode") scene_behavior: Optional[str] = Field(None, description="Scene behavior: complement|match") # daylight fields use_real_time: Optional[bool] = Field(None, description="Use wall-clock time instead of simulation") latitude: Optional[float] = Field(None, description="Geographic latitude (-90 to 90)", ge=-90.0, le=90.0) description: Optional[str] = Field(None, description="Optional description", max_length=500) tags: Optional[List[str]] = None class ValueSourceResponse(BaseModel): """Value source response.""" id: str = Field(description="Source ID") name: str = Field(description="Source name") source_type: str = Field(description="Source type: static, animated, audio, adaptive_time, or adaptive_scene") value: Optional[float] = Field(None, description="Static value") waveform: Optional[str] = Field(None, description="Waveform type") speed: Optional[float] = Field(None, description="Cycles per minute") min_value: Optional[float] = Field(None, description="Minimum output") max_value: Optional[float] = Field(None, description="Maximum output") audio_source_id: Optional[str] = Field(None, description="Mono audio source ID") mode: Optional[str] = Field(None, description="Audio mode") sensitivity: Optional[float] = Field(None, description="Gain multiplier") smoothing: Optional[float] = Field(None, description="Temporal smoothing") auto_gain: Optional[bool] = Field(None, description="Auto-normalize audio levels") schedule: Optional[list] = Field(None, description="Time-of-day schedule") picture_source_id: Optional[str] = Field(None, description="Picture source ID") scene_behavior: Optional[str] = Field(None, description="Scene behavior") use_real_time: Optional[bool] = Field(None, description="Use wall-clock time") latitude: Optional[float] = Field(None, description="Geographic latitude") description: Optional[str] = Field(None, description="Description") tags: List[str] = Field(default_factory=list, description="User-defined tags") created_at: datetime = Field(description="Creation timestamp") updated_at: datetime = Field(description="Last update timestamp") class ValueSourceListResponse(BaseModel): """List of value sources.""" sources: List[ValueSourceResponse] = Field(description="List of value sources") count: int = Field(description="Number of sources")