first_commit
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user