175 lines
4.2 KiB
Python
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)
|