from datetime import datetime from typing import Literal from pydantic import BaseModel, ConfigDict, Field class ScadaDeviceResponse(BaseModel): """Project SCADA metadata keyed by the canonical device identifier.""" device_id: str device_type: str node_id: str | None = None link_id: str | None = None api_query_id: str | None = None measurement_unit: str transmission_mode: str transmission_frequency: str reliability: int | None = None x: float | None = None y: float | None = None longitude: float | None = None latitude: float | None = None class ScadaLatestReadingResponse(BaseModel): """Latest persisted observation for one project SCADA device.""" model_config = ConfigDict(extra="forbid", allow_inf_nan=False) device_id: str device_type: str measurement_unit: str transmission_mode: str transmission_frequency: str observed_at: datetime | None = None monitored_value: float | None = None cleaned_value: float | None = None class ScadaLatestReadingsResponse(BaseModel): """Bounded device page with each device's latest persisted observation.""" model_config = ConfigDict(extra="forbid", allow_inf_nan=False) items: list[ScadaLatestReadingResponse] total: int = Field(ge=0) limit: int = Field(ge=1, le=500) offset: int = Field(ge=0) observed_count: int = Field(ge=0) latest_observed_at: datetime | None = None class ScadaRawReading(BaseModel): model_config = ConfigDict(extra="forbid", allow_inf_nan=False) time: datetime device_id: str monitored_value: float | None quality: Literal["unvalidated", "missing", "invalid"] = "unvalidated" class ScadaRawPage(BaseModel): model_config = ConfigDict(extra="forbid", allow_inf_nan=False) items: list[ScadaRawReading] next_cursor: str | None scanned_through: datetime