CI en échec sur ruff format (ligne trop longue) et mypy (retour Any non annoté, assignation Literal non étroite). Corrige sans changer le comportement.
90 lines
2.8 KiB
Python
90 lines
2.8 KiB
Python
from collections.abc import Sequence
|
|
from dataclasses import dataclass
|
|
from datetime import datetime
|
|
from typing import Literal
|
|
|
|
from app.models.energy import Site
|
|
from app.repositories.reading import ReadingRepository
|
|
from app.repositories.site import SiteRepository
|
|
|
|
DataQuality = Literal["good", "partial", "degraded", "critical"]
|
|
|
|
QUALITES_CONNUES: frozenset[str] = frozenset({"good", "partial", "degraded", "critical"})
|
|
|
|
|
|
class SiteError(Exception):
|
|
pass
|
|
|
|
|
|
class SiteNotFoundError(SiteError):
|
|
pass
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class SiteCurrentReading:
|
|
timestamp: datetime | None
|
|
site_id: str
|
|
site_type: str
|
|
consumption_kw: float | None
|
|
consumption_kwh: float | None
|
|
voltage_v: float | None
|
|
current_a: float | None
|
|
power_factor: float | None
|
|
temperature_celsius: float | None
|
|
humidity_percent: float | None
|
|
null_reasons: list[str]
|
|
data_quality: DataQuality
|
|
|
|
|
|
class SiteService:
|
|
def __init__(self, *, sites: SiteRepository, readings: ReadingRepository) -> None:
|
|
self._sites = sites
|
|
self._readings = readings
|
|
|
|
async def list_all(self) -> Sequence[Site]:
|
|
return await self._sites.list_all()
|
|
|
|
async def get_by_id(self, site_id: str) -> Site:
|
|
site = await self._sites.get_by_id(site_id)
|
|
if site is None:
|
|
raise SiteNotFoundError(site_id)
|
|
return site
|
|
|
|
async def current(self, site_id: str) -> SiteCurrentReading:
|
|
site = await self.get_by_id(site_id)
|
|
derniere = await self._readings.latest_for_site(site_id)
|
|
|
|
if derniere is None:
|
|
return SiteCurrentReading(
|
|
timestamp=None,
|
|
site_id=site.site_id,
|
|
site_type=site.site_type,
|
|
consumption_kw=None,
|
|
consumption_kwh=None,
|
|
voltage_v=None,
|
|
current_a=None,
|
|
power_factor=None,
|
|
temperature_celsius=None,
|
|
humidity_percent=None,
|
|
null_reasons=[],
|
|
data_quality="critical",
|
|
)
|
|
|
|
qualite: DataQuality = "critical"
|
|
if derniere.data_quality in QUALITES_CONNUES:
|
|
qualite = derniere.data_quality # type: ignore[assignment]
|
|
return SiteCurrentReading(
|
|
timestamp=derniere.timestamp,
|
|
site_id=site.site_id,
|
|
site_type=site.site_type,
|
|
consumption_kw=derniere.consumption_kw,
|
|
consumption_kwh=derniere.consumption_kwh,
|
|
voltage_v=derniere.voltage_v,
|
|
current_a=derniere.current_a,
|
|
power_factor=derniere.power_factor,
|
|
temperature_celsius=derniere.temperature_celsius,
|
|
humidity_percent=derniere.humidity_percent,
|
|
null_reasons=derniere.null_reasons or [],
|
|
data_quality=qualite,
|
|
)
|