from __future__ import annotations import logging from datetime import datetime, timedelta, timezone from app.aer.cache import refresh_plan_cache from app.config import settings from app.db.repositories import get_household_config, get_sync_state, set_sync_state, upsert_interval_readings from app.db.session import get_session from app.isolarcloud import get_isolarcloud_client _LOGGER = logging.getLogger(__name__) POLL_STATE_KEY = "isolarcloud_last_poll_ts" AER_STATE_KEY = "aer_last_refresh_ts" # Sungrow's own real-time data resolution is ~5 minutes -- don't try to # backfill further back than this on first run; a fresh install just starts # accumulating history from here. DEFAULT_BACKFILL = timedelta(days=1) def poll_isolarcloud_job() -> None: now = datetime.now(timezone.utc) with get_session() as session: last_poll = get_sync_state(session, POLL_STATE_KEY) since = datetime.fromisoformat(last_poll) if last_poll else now - DEFAULT_BACKFILL client = get_isolarcloud_client() try: points = client.fetch_interval_data(since, now) except Exception: _LOGGER.exception("iSolarCloud poll failed (since=%s)", since) return source = "mock" if settings.use_mock_isolarcloud else "isolarcloud" rows = [p.as_row(source) for p in points] with get_session() as session: inserted = upsert_interval_readings(session, rows) set_sync_state(session, POLL_STATE_KEY, now.isoformat()) _LOGGER.info("iSolarCloud poll: fetched %d points, inserted %d new rows", len(points), inserted) def refresh_aer_plans_job() -> None: with get_session() as session: distributor = get_household_config(session).distributor or settings.distributor try: count = refresh_plan_cache(distributor_filter=distributor) except Exception: _LOGGER.exception("AER plan refresh failed") return with get_session() as session: set_sync_state(session, AER_STATE_KEY, datetime.now(timezone.utc).isoformat()) _LOGGER.info("AER plan refresh: cached %d plans for distributor '%s'", count, distributor)