Files
solar-pv-dashboard/backend/app/models/definitions.py
Mateusz Gruszczyński c5cc2efbac first commit
2026-03-23 15:56:18 +01:00

175 lines
4.2 KiB
Python

from __future__ import annotations
from dataclasses import dataclass, field
from datetime import date, datetime
from typing import Any, Literal
MetricKind = Literal["gauge", "counter", "text"]
@dataclass(frozen=True)
class MetricDefinition:
id: str
entity_id: str
measurement: str
unit: str = ""
label: str = ""
kind: MetricKind = "gauge"
precision: int = 2
enabled: bool = True
@dataclass
class MetricValue:
metric_id: str
label: str
unit: str = ""
value: float | str | None = None
timestamp: datetime | None = None
precision: int = 2
kind: MetricKind = "gauge"
status: str = "neutral"
@dataclass
class SeriesPoint:
timestamp: datetime
value: float | None = None
@dataclass
class SeriesPayload:
metric_id: str
label: str
unit: str
points: list[SeriesPoint] = field(default_factory=list)
@dataclass
class SnapshotGroupRow:
id: str
label: str
values: dict[str, MetricValue] = field(default_factory=dict)
meta: dict[str, Any] = field(default_factory=dict)
@dataclass
class HeroCard:
metric_id: str
label: str
value: float | str | None = None
unit: str = ""
accent: str = "neutral"
subtitle: str = ""
@dataclass
class SnapshotPayload:
updated_at: datetime | None = None
hero_cards: list[HeroCard] = field(default_factory=list)
kpis: dict[str, MetricValue] = field(default_factory=dict)
strings: list[SnapshotGroupRow] = field(default_factory=list)
phases: list[SnapshotGroupRow] = field(default_factory=list)
status: list[MetricValue] = field(default_factory=list)
faults: list[str] = field(default_factory=list)
@dataclass
class BucketPoint:
label: str
start: datetime
end: datetime
value: float
@dataclass
class AnalyticsSummary:
total: float = 0.0
unit: str = "kWh"
average_bucket: float = 0.0
best_bucket_label: str = ""
best_bucket_value: float = 0.0
co2_saved_kg: float = 0.0
comparison_total: float | None = None
comparison_delta_pct: float | None = None
@dataclass
class DailyEnergyRecord:
day: date
energy_kwh: float
source: str
samples_count: int
imported_at: datetime | None = None
@dataclass
class HistoricalCoverage:
imported_days: int = 0
first_day: date | None = None
last_day: date | None = None
total_energy_kwh: float = 0.0
available_days: int = 0
missing_days: int = 0
coverage_pct: float | None = None
@dataclass
class HistoricalChunkProgress:
chunk_index: int
total_chunks: int
start_date: date
end_date: date
processed_days: int = 0
imported_days: int = 0
skipped_days: int = 0
energy_kwh: float = 0.0
state: str = "pending"
started_at: datetime | None = None
finished_at: datetime | None = None
duration_seconds: float | None = None
note: str = ""
@dataclass
class HistoricalActivityEvent:
timestamp: datetime
level: str = "info"
title: str = ""
message: str = ""
day: date | None = None
chunk_index: int | None = None
@dataclass
class HistoricalImportStatus:
enabled: bool = True
running: bool = False
state: str = "idle"
job_id: str | None = None
started_at: datetime | None = None
finished_at: datetime | None = None
requested_start_date: date | None = None
requested_end_date: date | None = None
total_days: int = 0
processed_days: int = 0
imported_days: int = 0
skipped_days: int = 0
chunk_days: int = 1
total_chunks: int = 0
active_chunk_index: int = 0
current_date: date | None = None
current_chunk_start: date | None = None
current_chunk_end: date | None = None
elapsed_seconds: float | None = None
estimated_remaining_seconds: float | None = None
avg_days_per_minute: float | None = None
last_error: str | None = None
message: str = ""
coverage: HistoricalCoverage = field(default_factory=HistoricalCoverage)
available_start_date: date | None = None
available_end_date: date | None = None
default_chunk_days: int = 1
recent_chunks: list[HistoricalChunkProgress] = field(default_factory=list)
recent_events: list[HistoricalActivityEvent] = field(default_factory=list)