Files
rpotter6298 c8e3016fd6 Add new daemons and debug scripts for Sigenergy and Oracle functionalities
- Implement `sigen_daemon.py` to poll Sigenergy plant metrics and store snapshots.
- Create `web_daemon.py` for serving a web interface with various endpoints.
- Add debug scripts:
  - `debug_duplicates.py` to find duplicate target times in forecast data.
  - `debug_energy_forecast.py` to print baseline energy forecast curves.
  - `debug_oracle_evaluations.py` to run the oracle evaluator.
  - `debug_sigen.py` to inspect stored Sigenergy plant snapshots.
  - `debug_weather.py` to trace resolved truth data.
  - `modbus_test.py` for exploring Sigenergy plants or inverters over Modbus TCP.
- Introduce `oracle_evaluator.py` for evaluating stored oracle predictions against actuals.
- Add TCN training scripts in `tcn` directory for training usage sequence models.
2026-04-28 08:14:00 +02:00

96 lines
2.5 KiB
Python

from __future__ import annotations
import argparse
from dataclasses import dataclass
from os import environ
from sys import stderr
from time import sleep
from gibil.classes.env_loader import EnvLoader
from gibil.classes.sigen.builder import SigenPlantClient
from gibil.classes.sigen.store import SigenStore
@dataclass(frozen=True)
class SigenDaemonConfig:
poll_seconds: float
@classmethod
def from_env(cls) -> "SigenDaemonConfig":
return cls(
poll_seconds=float(environ.get("SIGEN_POLL_SECONDS", "5")),
)
class SigenDaemon:
"""Polls Sigenergy plant metrics and stores normalized snapshots."""
def __init__(
self,
config: SigenDaemonConfig,
plant_client: SigenPlantClient,
sigen_store: SigenStore,
) -> None:
self.config = config
self.plant_client = plant_client
self.sigen_store = sigen_store
@classmethod
def from_env(cls) -> "SigenDaemon":
return cls(
config=SigenDaemonConfig.from_env(),
plant_client=SigenPlantClient.from_env(),
sigen_store=SigenStore.from_env(),
)
def initialize(self) -> None:
self.sigen_store.initialize()
def run_once(self) -> int:
snapshot = self.plant_client.fetch_snapshot()
return self.sigen_store.save_snapshot(snapshot)
def run_forever(self) -> None:
self.initialize()
while True:
try:
saved_count = self.run_once()
print(f"stored_sigen_plant_snapshots={saved_count}", flush=True)
except Exception as error:
print(f"sigen_poll_error={error}", file=stderr, flush=True)
sleep(self.config.poll_seconds)
def main() -> None:
try:
EnvLoader().load()
daemon = SigenDaemon.from_env()
args = parse_args()
if args.once:
daemon.initialize()
saved_count = daemon.run_once()
print(f"stored_sigen_plant_snapshots={saved_count}", flush=True)
return
daemon.run_forever()
except Exception as error:
print(f"sigen_daemon_startup_error={error}", file=stderr)
raise SystemExit(1) from error
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Poll Sigenergy plant metrics into Astrape's database."
)
parser.add_argument(
"--once",
action="store_true",
help="Initialize storage, save one snapshot, and exit.",
)
return parser.parse_args()
if __name__ == "__main__":
main()