from pydantic import BaseModel, Field from typing import Optional, List, Any, Dict from enum import Enum class LogLevel(str, Enum): INFO = "INFO" WARN = "WARN" ERROR = "ERROR" class CommandStatus(str, Enum): PENDING = "pending" SUCCESS = "success" ERROR = "error" TIMEOUT = "timeout" class MqttCommandRequest(BaseModel): cmd: str = Field(..., description="Command name: ping, playback, file_manager, relay_setup, clock_setup, system_info, system") contents: Dict[str, Any] = Field(default_factory=dict, description="Command payload contents") class DeviceLogEntry(BaseModel): id: int device_serial: str level: str message: str device_timestamp: Optional[int] = None received_at: str class HeartbeatEntry(BaseModel): id: int device_serial: str device_id: Optional[str] = None firmware_version: Optional[str] = None ip_address: Optional[str] = None gateway: Optional[str] = None uptime_ms: Optional[int] = None uptime_display: Optional[str] = None received_at: str class CommandEntry(BaseModel): id: int device_serial: str command_name: str command_payload: Optional[str] = None status: str response_payload: Optional[str] = None sent_at: str responded_at: Optional[str] = None class DeviceMqttStatus(BaseModel): device_serial: str online: bool last_heartbeat: Optional[HeartbeatEntry] = None seconds_since_heartbeat: Optional[int] = None class MqttStatusResponse(BaseModel): devices: List[DeviceMqttStatus] broker_connected: bool = False class LogListResponse(BaseModel): logs: List[DeviceLogEntry] total: int class HeartbeatListResponse(BaseModel): heartbeats: List[HeartbeatEntry] total: int class CommandListResponse(BaseModel): commands: List[CommandEntry] total: int class CommandSendResponse(BaseModel): success: bool command_id: int message: str