Some checks failed
Lint & Test / test (push) Failing after 28s
Replace 22 individual JSON store files with a single SQLite database (data/ledgrab.db). All entity stores now use BaseSqliteStore backed by SQLite with WAL mode, write-through caching, and thread-safe access. - Add Database class with SQLite backup/restore API - Add BaseSqliteStore as drop-in replacement for BaseJsonStore - Convert all 16 entity stores to SQLite - Move global settings (MQTT, external URL, auto-backup) to SQLite settings table - Replace JSON backup/restore with SQLite snapshot backups (.db files) - Remove partial export/import feature (backend + frontend) - Update demo seed to write directly to SQLite - Add "Backup Now" button to settings UI - Remove StorageConfig file path fields (single database_file remains)
172 lines
6.7 KiB
Python
172 lines
6.7 KiB
Python
"""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")
|
|
demo_mode: bool = Field(default=False, description="Whether demo mode is active")
|
|
auth_required: bool = Field(default=True, description="Whether API key authentication is required")
|
|
|
|
|
|
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")
|
|
demo_mode: bool = Field(default=False, description="Whether demo mode is active")
|
|
|
|
|
|
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 database backup."""
|
|
|
|
status: str = Field(description="Status of restore operation")
|
|
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)")
|