Add finalized energy history import for Ohme#169679
Add finalized energy history import for Ohme#169679tstordyallison wants to merge 9 commits intohome-assistant:devfrom
Conversation
There was a problem hiding this comment.
It seems you haven't yet signed a CLA. Please do so here.
Once you do that we will be able to review and accept this pull request.
Thanks!
|
Hey there @dan-r, mind taking a look at this pull request as it has been labeled with an integration ( Code owner commandsCode owners of
|
There was a problem hiding this comment.
Pull request overview
This PR adds a statistics-only finalized energy-history import path to the Ohme integration so Home Assistant can backfill and repair recorder statistics for charging energy without introducing a new user-facing sensor entity.
Changes:
- Adds new history import/rebuild/recovery helpers for finalized Ohme charging data and wires them into integration startup.
- Extends the charge-session coordinator to trigger bounded re-imports on session finalization, delayed retries, and daily repair syncs.
- Adds an options flow and supporting tests/snapshots for configurable history backfill and the updated sensor naming/behavior.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
homeassistant/components/ohme/__init__.py |
Initializes history sync during setup and toggles sync orchestration on load/unload. |
homeassistant/components/ohme/config_flow.py |
Adds an options flow for backfill_days and stores default options on initial setup. |
homeassistant/components/ohme/const.py |
Defines new history/backfill-related constants. |
homeassistant/components/ohme/coordinator.py |
Adds session-finalization detection, queued history syncs, delayed retry, and daily repair scheduling. |
homeassistant/components/ohme/history.py |
Implements recorder-statistics import, rebuild, recovery, and bounded repair logic. |
homeassistant/components/ohme/manifest.json |
Switches the integration dependency to a branch-based ohme package source. |
homeassistant/components/ohme/sensor.py |
Renames the live energy sensor translation and keeps sensor setup aligned with runtime data. |
homeassistant/components/ohme/services.py |
Refactors config-entry lookup helpers and guards against duplicate service registration. |
homeassistant/components/ohme/strings.json |
Adds options-flow strings and the new sensor translation. |
tests/components/ohme/conftest.py |
Extends the mock Ohme client with summary/session-history fields and defaults. |
tests/components/ohme/snapshots/test_sensor.ambr |
Updates sensor snapshots for the renamed energy sensor and metadata changes. |
tests/components/ohme/test_config_flow.py |
Covers default options on setup and the new options flow. |
tests/components/ohme/test_history.py |
Adds focused coverage for bootstrap, rebuild/recovery, session-finalization syncs, retries, and repair windows. |
tests/components/ohme/test_sensor.py |
Updates live sensor expectations and adds coverage for non-fatal summary failures at setup. |
| "quality_scale": "platinum", | ||
| "requirements": ["ohme==1.9.0"] | ||
| "requirements": [ | ||
| "ohme @ git+https://github.com/tstordyallison/ohmepy.git@public-session-timestamps-and-summary-granularity" |
@dan-r before I can sign the CLA - I need some internal approvals from my employer. Shouldn't be a problem (HA isn't exactly a trading platform!) but will take a few days. |
0c98b7e to
1cfb5d9
Compare
There was a problem hiding this comment.
It seems you haven't yet signed a CLA. Please do so here.
Once you do that we will be able to review and accept this pull request.
Thanks!
There was a problem hiding this comment.
It seems you haven't yet signed a CLA. Please do so here.
Once you do that we will be able to review and accept this pull request.
Thanks!
There was a problem hiding this comment.
It seems you haven't yet signed a CLA. Please do so here.
Once you do that we will be able to review and accept this pull request.
Thanks!
There was a problem hiding this comment.
It seems you haven't yet signed a CLA. Please do so here.
Once you do that we will be able to review and accept this pull request.
Thanks!
|
Woah, the co-pilot review really kicked in! I'll take a look at the comments and see what's what. They look like the are probably right! |
There was a problem hiding this comment.
It seems you haven't yet signed a CLA. Please do so here.
Once you do that we will be able to review and accept this pull request.
Thanks!
There was a problem hiding this comment.
It seems you haven't yet signed a CLA. Please do so here.
Once you do that we will be able to review and accept this pull request.
Thanks!
| entry.runtime_data.charge_session_coordinator.disable_history_sync() | ||
| return await hass.config_entries.async_unload_platforms(entry, PLATFORMS) |
| StatisticData(start=window_start, state=current_sum, sum=current_sum) | ||
| ) | ||
|
|
||
| for bucket_start, bucket_kwh in hourly_points: | ||
| current_sum = round(current_sum + bucket_kwh, 6) | ||
| statistics.append( | ||
| StatisticData(start=bucket_start, state=current_sum, sum=current_sum) |
| stats = await get_instance(hass).async_add_executor_job( | ||
| statistics_during_period, | ||
| hass, | ||
| FULL_HISTORY_START, | ||
| end, | ||
| {stat_id}, | ||
| "hour", | ||
| None, | ||
| {"sum"}, | ||
| ) | ||
| rows = stats.get(stat_id, []) | ||
| if not rows: | ||
| return 0.0 | ||
| last_sum = rows[-1]["sum"] | ||
| return float(last_sum) if last_sum is not None else 0.0 | ||
|
|
||
|
|
There was a problem hiding this comment.
It seems you haven't yet signed a CLA. Please do so here.
Once you do that we will be able to review and accept this pull request.
Thanks!
There was a problem hiding this comment.
It seems you haven't yet signed a CLA. Please do so here.
Once you do that we will be able to review and accept this pull request.
Thanks!
There was a problem hiding this comment.
It seems you haven't yet signed a CLA. Please do so here.
Once you do that we will be able to review and accept this pull request.
Thanks!
Summary
Approach
This keeps the live Ohme entity model unchanged and imports finalized charge history into recorder as an external statistic, rather than introducing a new dedicated
total_charged_energysensor entity.Sync Model
backfill_dayschange triggers a rebuild of the configured history window.MONTHsummary calls to prefilter active ranges, then fetchHOURbuckets only inside those ranges.HOURbuckets directly.Why Statistics-Only
I chose the statistics-only route because it keeps the integration surface smaller and avoids introducing another user-facing sensor whose main purpose would be Energy Dashboard compatibility.
That does mean the imported energy history is authoritative in recorder/statistics rather than as a dedicated entity state.
Similar Patterns In Core
This is not totally novel in Home Assistant core. A few existing energy-focused integrations already manage external recorder statistics from provider-owned historical data rather than relying only on live entity history:
tibberimports historic hourly consumption/production into external statistics and continues from the existing statistic state: https://github.com/home-assistant/core/blob/dev/homeassistant/components/tibber/coordinator.py#L183-L275elviaimports verified meter values into external statistics and resumes from the last imported point: https://github.com/home-assistant/core/blob/dev/homeassistant/components/elvia/importer.py#L61-L150solaredgealso builds external energy statistics and reconstructs sums around the target import window: https://github.com/home-assistant/core/blob/dev/homeassistant/components/solaredge/coordinator.py#L500-L560The Ohme version here is a bit more session/finalization-driven because of the API shape, but the general pattern of using imported external statistics as the authoritative long-term energy history is already established elsewhere in core.
Tradeoffs / Known Non-Ideal Areas
backfill_daysoption change currently triggers a rebuild of the configured history window. That is simple and robust, but not the cheapest possible path for very large histories. It's probably what you want if you tweak it to go further back though.total_charged_energyentity. I did try having one but HA gets very unhappy if you make it the same one. We could always add it on the side just as a number, but my fear is people would select it in the Energy dashboard and it wouldn't work properly (we couldn't update the past and the updates would be in the wrong buckets).Feedback Areas
Companion Dependency
This draft intentionally depends on the companion
ohmepychange that exposes publicsession_start/session_finishaccessors and restoresMONTHsummary granularity:Testing
python -m compileall homeassistant/components/ohme tests/components/ohmepython -m pytest -q tests/components/ohme/test_sensor.py tests/components/ohme/test_init.py tests/components/ohme/test_history.py19 passed15 snapshots passed