Skip to content

Releases: yeaxi/solar-analytics

Release list

v2.3.0

Choose a tag to compare

@yeaxi yeaxi released this 18 Aug 15:37
7258784

Added

  • Generalized the forecast source. Solar Analytics is no longer Forecast.Solar
    only. The Energy Dashboard adapter binds to any integration that provides the
    Home Assistant solar-forecast platform (Forecast.Solar, Solcast, ...),
    resolving the helper through the Energy platform registry rather than a
    core-only import. A new forecast_entity source type reads a timestamped
    Wh-per-period profile (wh_hours, wh_period, or watt_hours_period) from a
    chosen forecast entity, rejects restored states and non-Wh units, and admits
    from profile horizon coverage plus a read-only state-change listener. Both
    remain read-only and fail closed. An entity that exposes no timestamped
    profile is rejected with the new unsupported_forecast_entity_contract
    status; no energy is fabricated from a scalar. Config-entry version 6 adds
    forecast_source_type and forecast_entity_id. Forecast.Solar keeps its
    exact model fingerprint, listener/wh_period gates, and lineage key join;
    non-Forecast.Solar Energy providers admit on a valid helper payload.
  • Soak checkpoint schema version 3. Collector envelopes must declare
    forecast_source_type (energy_entry with provider_domain, or
    forecast_entity); required fresh logs follow that source, and the soak
    window must be at least 24 hours.
  • Imported historical actual production. On setup Solar Analytics reads the
    configured actual PV energy sensor's long-term Recorder statistics
    (hourly, never purged) through statistics_during_period on the Recorder's
    own executor, derives each local day's kWh from the cumulative sum deltas,
    and stores them in the new v2_imported_actual_daily table. Counter resets
    are recorded rather than turned into negative days, and each day carries the
    fraction of its hours that were observed, measured against the real 23, 24 or
    25 hours of that local day.
  • New sensor.solar_analytics_imported_actual_history diagnostic entity,
    disabled by default, carrying the bounded daily points, the import status,
    and an explicit reconstructed_from_recorder_statistics provenance label.
    Imported actuals are not wired into valid_paired_day, the rolling
    accuracy window, or WAPE, and they do not shorten the 14-day accuracy
    warm-up. Home Assistant never persists the timestamped forecast profile to
    any state, so there is no recorded historical forecast to pair them against,
    and splitting the one logged daily forecast scalar across hours is forbidden
    by rule 4 of the recorder/forecast contract.
  • scripts/verify_import_idempotency.py, a deterministic rerunnable check that
    the import converges: it feeds a synthetic year of hourly statistics through
    the real reconstruction and the real store write three times and compares the
    row count and total kWh.
  • Read-only scanner coverage for the write paths this feature invites:
    async_import_statistics, async_add_external_statistics,
    async_adjust_statistics, hass.states.async_set,
    hass.states.async_remove, any reference to the live Recorder database file,
    and an assertion that sqlite3 stays imported only by storage_v2.py.
  • recorder in manifest.json after_dependencies (an ordering hint, not a
    hard dependency: the entry still loads and reports recorder_unavailable).

Changed

  • Removed the always-None Victron VRM forecast sensor and its payload keys.
    User-facing labels, repair issues, and device model copy are now
    provider-neutral ("Forecast power", "Forecast source status"); the underlying
    entity ids, unique ids, status enum values, and payload keys are unchanged, so
    existing dashboards and automations keep working.

  • Generic Energy provider model identity is digest-only (domain + entry id);
    foreign config scalars no longer appear in state, diagnostics, or SQLite.
    Lineage reuse is scoped to the configured source, so switching forecast
    source cannot keep writing accuracy onto the previous lineage. Payload
    provenance (source_map.forecast, native_update_time_source) now names the
    path that actually admitted the profile. forecast_solar moved from
    dependencies to after_dependencies.

  • Shipping version 2.3.0 participates in the lineage contract_key via
    NATIVE_ADAPTER_VERSION. Existing installs start a new accuracy lineage on
    upgrade; the Forecast.Solar fingerprint and gate logic themselves are
    unchanged.

    Evidence status for the import is PARTIAL. Home Assistant is not
    installed in CI, so the Recorder call is exercised against a recording stub.
    What is verified is the reconstruction arithmetic, the storage idempotency,
    and that exactly one statistic id is requested through the read API with no
    mutating call. What is not verified is live Recorder behaviour on a real
    installation. Do not claim this path production-ready without that evidence.

  • Pinned requirements-dev.txt and Dependabot updates for GitHub Actions
    and pip so CI tool versions stop floating.

  • Hermetic tests that strings.json, translations/en.json, and
    translations/uk.json share the same key tree, and that
    pyproject.toml version matches manifest.json.

  • GitHub Pages docs site (MkDocs Material) at https://yeaxi.github.io/solar-analytics/.

  • Home Assistant brand assets at custom_components/solar_analytics/brand/
    (icon.png 256x256 and icon@2x.png 512x512) so HACS renders a proper icon
    for the integration and the "brands" validator passes without a
    home-assistant/brands submission.

  • Coordinator now emits a single warning log when the native Forecast.Solar
    binding becomes unavailable and a matching info log when it recovers;
    repeated identical statuses no longer log per 5-minute poll (silver-tier
    "log-when-unavailable" pattern).

  • CONTRIBUTING.md documents the one-time GitHub-side owner setup (repository
    description, topics, and GitHub Pages source).

  • Tag-triggered GitHub Release workflow. scripts/release.py checks that the
    tag, manifest.json, pyproject.toml, and CHANGELOG heading agree, extracts
    the changelog body as release notes, and attaches solar_analytics.zip for
    manual installs. HACS still installs from the tagged tree (zip_release
    stays false).

Removed

  • The six never-used v2_backfill_* tables and their eight store APIs. They
    had no callers and no tests, could not express the
    observed_at_utc <= scheduled_at_utc admissibility rule (no scheduled_at_utc
    column), had a nullable column inside a PRIMARY KEY so their ON CONFLICT
    never fired, and were never pruned. Storage schema version 5 drops all six on
    first open; nothing read them, so nothing is lost.
  • native.period_coverage_seconds and the native.parse_native_profile
    compatibility alias, both unreferenced.
  • native._canonical_wh_hours, also unreferenced. Its one rule, dropping a
    zero point at exact midnight, belonged to no shipped path;
    normalize_native_wh_hours keeps a non-midnight zero boundary and
    quarantines the first cell instead.
  • scripts/recorder_backfill_report.py and its two ruff.toml per-file
    exceptions. The script opened an archived Recorder database directly and
    rebuilt daily rows from states, which duplicated the shipped importer. It
    could only recover a daily forecast scalar, and rule 4 of the recorder and
    forecast contract forbids feeding that into accuracy. The scripts/
    inventory in CONTRIBUTING.md now names verify_import_idempotency.py, the
    one script left. The 2.2.1 note about the report stays as written; it was
    true for that release.

Changed

  • CI tests and lint now run on Python 3.14 (Home Assistant 2026.7 runtime)
    with least-privilege permissions, concurrency cancellation, job
    timeouts, and a split lint/pytest job. Docs Pages write permission is
    limited to the deploy job.
  • README is now end-user only (install, setup, troubleshooting, bug reports).
    Contributor, agent, and architecture docs stay in CONTRIBUTING.md,
    AGENTS.md, and docs/architecture/.
  • manifest.json documentation URL now points at the docs site.
  • hacs.json: removed the invalid "hacs" key that made the HACS validator
    reject the manifest; explicitly declared "zip_release": false.

Fixed

  • Daily coverage could never clear its 95% / 90% gate, so
    sensor.solar_analytics_analysis_status was stuck on insufficient_data
    and forecast accuracy never became ready. Forecast.Solar reports the whole
    night as one zero-Wh period straddling local midnight, and every
    boundary-crossing period was dropped, leaving only daylight in a numerator
    divided by a full day. A zero-Wh period is now clipped at local midnight and
    counted for both adjacent days; a boundary-crossing period that carries
    energy is still excluded rather than apportioned by time. Existing days are
    recomputed from the stored immutable snapshots, so the correction applies to
    history already on disk.
  • Day length is now measured between two UTC instants instead of two local
    datetimes sharing a timezone, which always reported 24 hours. DST transition
    days are measured against their real 23 or 25 hours, and the three coverage
    ratios are clamped at 1.0.
  • Every five-minute cycle re-read the whole accumulator table and rebuilt the
    interval rows of every retained day, including days that finished weeks ago.
    integrate_accumulators now bounds its read on both sides of the requested
    window, from one 30-minute bucket before the start through the end, and
    interval rebuilding stops at a finalization marker in v2_runtime_state so a
    finished local day is built once. Measured over 17,520 buckets (365 days) with
    a one-hour window, 25 runs: 17,520 rows fetched down to 3, median 21.682 ms
    down to 0.008 ms, window total unchanged at 200.0 Wh and 3,600.0 covered
    seconds. Rerun it with python scripts/benchmark_accumulator_window.py.
  • A direct upgrade still repairs history. The marker carries its own
    `INTERVAL_BUILD_REVISION...
Read more

v0.1.0

Choose a tag to compare

@yeaxi yeaxi released this 14 Aug 09:01

What's Changed

  • Add multi-perspective-project-analysis skill by @yeaxi in #1
  • Reusable, platinum-quality Solar Analytics refactor by @yeaxi in #2
  • Platinum follow-ups: parallelism, translations, mypy, hassfest, repairs, payload split by @yeaxi in #3
  • HACS validation fixes, brand assets, unavailable-transition logging, 2.2.1 by @yeaxi in #4
  • Split user README from contributor docs and publish GitHub Pages by @yeaxi in #6
  • Harden CI for Python 3.14 and pin the dev toolchain by @yeaxi in #7
  • Fix the daily coverage gate so a valid paired day is reachable by @yeaxi in #16
  • Import historical actual production from the Recorder, and delete the dead backfill scaffolding by @yeaxi in #17
  • Remove the obsolete Recorder backfill path by @yeaxi in #18
  • Bound accumulator reads to the requested window by @yeaxi in #19
  • Stop rebuilding finalized interval history every five minutes by @yeaxi in #20

Full Changelog: https://github.com/yeaxi/solar-analytics/commits/v0.1.0