64 lines
2.1 KiB
Python
64 lines
2.1 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime, timezone
|
|
|
|
from gibil.classes.models import Observation, ObservationQuality, Snapshot
|
|
|
|
|
|
class SnapshotBuilder:
|
|
"""Builds Gibil's decision input from the latest observations."""
|
|
|
|
def build(self, observations: list[Observation]) -> Snapshot:
|
|
latest = self._latest_by_metric(observations)
|
|
|
|
return Snapshot(
|
|
created_at=datetime.now(timezone.utc),
|
|
solar_power_w=self._number(latest, "solar_power_w"),
|
|
home_power_w=self._number(latest, "home_power_w"),
|
|
battery_soc_pct=self._number(latest, "battery_soc_pct"),
|
|
grid_import_w=self._number(latest, "grid_import_w"),
|
|
grid_export_w=self._number(latest, "grid_export_w"),
|
|
cheap_window_active=self._boolean(latest, "cheap_window_active"),
|
|
input_quality={
|
|
metric: observation.quality for metric, observation in latest.items()
|
|
},
|
|
)
|
|
|
|
def _latest_by_metric(
|
|
self, observations: list[Observation]
|
|
) -> dict[str, Observation]:
|
|
latest: dict[str, Observation] = {}
|
|
|
|
for observation in observations:
|
|
existing = latest.get(observation.metric)
|
|
if existing is None or observation.observed_at > existing.observed_at:
|
|
latest[observation.metric] = observation
|
|
|
|
return latest
|
|
|
|
def _number(
|
|
self, observations: dict[str, Observation], metric: str
|
|
) -> float | None:
|
|
observation = observations.get(metric)
|
|
if observation is None or observation.quality != ObservationQuality.OK:
|
|
return None
|
|
|
|
if isinstance(observation.value, bool):
|
|
return None
|
|
|
|
if isinstance(observation.value, int | float):
|
|
return float(observation.value)
|
|
|
|
return None
|
|
|
|
def _boolean(self, observations: dict[str, Observation], metric: str) -> bool:
|
|
observation = observations.get(metric)
|
|
if observation is None or observation.quality != ObservationQuality.OK:
|
|
return False
|
|
|
|
if isinstance(observation.value, bool):
|
|
return observation.value
|
|
|
|
return False
|
|
|