"""System-related schemas (health, version, displays).""" from datetime import datetime from typing import List, Literal from pydantic import BaseModel, Field class HealthResponse(BaseModel): """Health check response.""" status: Literal["healthy", "unhealthy"] = Field(description="Service health status") timestamp: datetime = Field(description="Current server time") version: str = Field(description="Application version") class VersionResponse(BaseModel): """Version information response.""" version: str = Field(description="Application version") python_version: str = Field(description="Python version") api_version: str = Field(description="API version") class DisplayInfo(BaseModel): """Display/monitor information.""" index: int = Field(description="Display index") name: str = Field(description="Display name") width: int = Field(description="Display width in pixels") height: int = Field(description="Display height in pixels") x: int = Field(description="Display X position") y: int = Field(description="Display Y position") is_primary: bool = Field(default=False, description="Whether this is the primary display") refresh_rate: int = Field(description="Display refresh rate in Hz") class DisplayListResponse(BaseModel): """List of available displays.""" displays: List[DisplayInfo] = Field(description="Available displays") count: int = Field(description="Number of displays") class ProcessListResponse(BaseModel): """List of running processes.""" processes: List[str] = Field(description="Sorted list of unique process names") count: int = Field(description="Number of unique processes") class GpuInfo(BaseModel): """GPU performance information.""" name: str | None = Field(default=None, description="GPU device name") utilization: float | None = Field(default=None, description="GPU core usage percent") memory_used_mb: float | None = Field(default=None, description="GPU memory used in MB") memory_total_mb: float | None = Field(default=None, description="GPU total memory in MB") temperature_c: float | None = Field(default=None, description="GPU temperature in Celsius") class PerformanceResponse(BaseModel): """System performance metrics.""" cpu_name: str | None = Field(default=None, description="CPU model name") cpu_percent: float = Field(description="System-wide CPU usage percent") ram_used_mb: float = Field(description="RAM used in MB") ram_total_mb: float = Field(description="RAM total in MB") ram_percent: float = Field(description="RAM usage percent") gpu: GpuInfo | None = Field(default=None, description="GPU info (null if unavailable)") timestamp: datetime = Field(description="Measurement timestamp") class RestoreResponse(BaseModel): """Response after restoring configuration backup.""" status: str = Field(description="Status of restore operation") stores_written: int = Field(description="Number of stores successfully written") stores_total: int = Field(description="Total number of known stores") missing_stores: List[str] = Field(default_factory=list, description="Store keys not found in backup") restart_scheduled: bool = Field(description="Whether server restart was scheduled") message: str = Field(description="Human-readable status message") # ─── Auto-backup schemas ────────────────────────────────────── class AutoBackupSettings(BaseModel): """Settings for automatic backup.""" enabled: bool = Field(description="Whether auto-backup is enabled") interval_hours: float = Field(ge=0.5, le=168, description="Backup interval in hours") max_backups: int = Field(ge=1, le=100, description="Maximum number of backup files to keep") class AutoBackupStatusResponse(BaseModel): """Auto-backup settings plus runtime status.""" enabled: bool interval_hours: float max_backups: int last_backup_time: str | None = None next_backup_time: str | None = None class BackupFileInfo(BaseModel): """Information about a saved backup file.""" filename: str size_bytes: int created_at: str class BackupListResponse(BaseModel): """List of saved backup files.""" backups: List[BackupFileInfo] count: int # ─── MQTT schemas ────────────────────────────────────────────── class MQTTSettingsResponse(BaseModel): """MQTT broker settings response (password is masked).""" enabled: bool = Field(description="Whether MQTT is enabled") broker_host: str = Field(description="MQTT broker hostname or IP") broker_port: int = Field(ge=1, le=65535, description="MQTT broker port") username: str = Field(description="MQTT username (empty = anonymous)") password_set: bool = Field(description="Whether a password is configured") client_id: str = Field(description="MQTT client ID") base_topic: str = Field(description="Base topic prefix") class MQTTSettingsRequest(BaseModel): """MQTT broker settings update request.""" enabled: bool = Field(description="Whether MQTT is enabled") broker_host: str = Field(description="MQTT broker hostname or IP") broker_port: int = Field(ge=1, le=65535, description="MQTT broker port") username: str = Field(default="", description="MQTT username (empty = anonymous)") password: str = Field(default="", description="MQTT password (empty = keep existing if omitted)") client_id: str = Field(default="ledgrab", description="MQTT client ID") base_topic: str = Field(default="ledgrab", description="Base topic prefix") # ─── External URL schema ─────────────────────────────────────── class ExternalUrlResponse(BaseModel): """External URL setting response.""" external_url: str = Field(description="External base URL (e.g. https://myserver.example.com:8080). Empty = use auto-detected URL.") class ExternalUrlRequest(BaseModel): """External URL setting update request.""" external_url: str = Field(default="", description="External base URL. Empty string to clear.") # ─── Log level schemas ───────────────────────────────────────── class LogLevelResponse(BaseModel): """Current log level response.""" level: str = Field(description="Current effective log level name (e.g. DEBUG, INFO, WARNING, ERROR, CRITICAL)") class LogLevelRequest(BaseModel): """Request to change the log level.""" level: str = Field(description="New log level name (DEBUG, INFO, WARNING, ERROR, CRITICAL)")