Skip to content

feat(fetch): warn when car_energy_reported_load is On but the load sensor excludes the charger - #5320

Open
chalfontchubby wants to merge 10 commits into
mainfrom
feat/warn-car-energy-reported-load-5318
Open

chalfontchubby wants to merge 10 commits into
mainfrom
feat/warn-car-energy-reported-load-5318

Conversation

@chalfontchubby

@chalfontchubby chalfontchubby commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Written by Claude, on behalf of @chalfontchubby.

Fixes #5318 (part 2; part 1 is declined on the issue, with the workaround).

Summary

With switch.predbat_car_energy_reported_load On (the default), Predbat assumes the car charger is inside the house load sensor. If it isn't, two things go wrong and nothing in the logs says why:

A load sensor that includes the charger can never read less than the charger's own energy over the same period. This PR checks that, and logs a warning once when it clearly fails:

Warn: car_charging_energy recorded more than twice the house load in N half hours of the last day, so the load sensor cannot include that charging, but switch.predbat_car_energy_reported_load is On. If car_charging_energy is only the car charger, turn the switch Off, and set car_charging_now to the charger's charging power or status sensor ...

How it decides

  • check_car_energy_reported_load() runs in fetch_sensor_data() straight after load_car_energy(), when both series are still raw. It runs only for the live plan (save=True), not for the per-tariff re-fetches the tariff comparison makes, so a comparison tariff that turns the switch Off can't reset the warning.
  • It looks at the last day in 30-minute windows. A window counts when the charger delivered at least 1 kWh and more than twice the house load.
  • It warns at 2 or more such windows. The warning is not logged again until no window shows the mismatch.
  • Lag between the sensors: a ratio alone only tolerates lag in windows wholly inside a charge. Where a session starts or ends part-way through a window, a lagging sensor shows only part of that charge. So a window counts only if the car energy is more than twice the load in that window shifted by every offset up to 15 minutes either way (CAR_ENERGY_LOAD_CHECK_LAG).
  • Windows with no house load at all are skipped. A house always draws something, so a flat stretch means the load sensor is missing data. The history is padded, so missing minutes read as zero.
  • The window in progress is left out, because a cloud-polled load sensor can run many minutes behind the charger.
  • The constants are CAR_ENERGY_LOAD_CHECK_* in const.py. docs/car-charging.md describes the warning under the switch.

Checked on #5317's debug dump: it fires on 7 of the last 24 half hours. The car recorded 2.6 to 3.5 kWh per half hour against 0.3 to 1.0 kWh of house load, and the lowest ratio against the shifted load is 2.7.

Testing

tests/test_car_energy_reported_load.py, registered as car_energy_reported_load, covers:

  • a charger outside the load sensor (warns once, and again after the mismatch clears)
  • a charger inside it, including 7 kW with ±5-minute lag and 11 kW over two sessions with ±5 and 10-minute lag (silent)
  • the switch Off; a single mismatched window; no data; the end of the history
  • a gap in the load data; the window in progress; the re-arm rule
  • sessions that start and end part-way through a window with the load sensor ±10/±15 minutes out (silent), and the same sessions with the charger outside the load sensor (warns)
  • the real fetch_sensor_data() over a live cycle (warns), a comparison run with save=False and the switch Off, and the next live cycle: the warning is logged once, not re-armed by the comparison run

Each rule was checked by disabling it and confirming its test fails. ./run_all --quick and ./run_pre_commit pass.

Not addressed

  • Log only. Nothing is recorded on the status sensor, because this is a heuristic and I didn't want a false positive to show as an error.
  • No auto-correction. Predbat keeps subtracting car energy and applying the low-load test until the user changes the setting.
  • Mixed setups. One charger inside the CT clamp and one outside can't be represented by the single switch. The advice is worded conditionally for that reason, and because the docs still allow non-car loads in car_charging_energy.
  • Large lags and long outages. A load sensor lagging more than about 30 minutes, or out for hours over a charge (interpolated across the gap), can still produce a false warning.

Possible follow-ups

  • Falling back to car_charging_power (documented as car only) as car_charging_now evidence when car_charging_now isn't set.

🤖 Generated with Claude Code

chalfontchubby and others added 3 commits September 30, 2026 14:55
…nsor excludes the charger (#5318)

With switch.predbat_car_energy_reported_load On, Predbat subtracts
car_charging_energy from the load history and, for an Octopus
Intelligent car without car_charging_now, reads low house load as the
car not charging. Against a load sensor that excludes the charger, the
first empties the load history and the second cancels dispatches that
are really charging (#5317) - and nothing in the logs pointed at it.

A load sensor that includes the charger can never read less than the
charger's own energy over the same window, so count the half hours of
the last day where car_charging_energy beat the load by a margin (1 kWh
minimum, 0.5 kWh margin to absorb lag between the two sensors) and log a
one-time Warn: at two or more, suggesting the switch be turned Off and
car_charging_now set to the charger's power or status sensor. On
#5317's debug dump it fires on 8 of the last 24 half hours.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lag and gaps (#5318 review)

- A window now needs the charger's energy to exceed twice the load
  rather than the load plus 0.5 kWh: at 11 kW a 5 minute lag between
  the two sensors already moves 0.9 kWh, so a fixed margin warned on a
  correctly configured system. A ratio tolerates a lag of up to half
  the window at any charger power; #5317's windows are all above 2.
- A window with no load at all is skipped - a house always draws
  something, so a flat stretch is the load sensor missing data.
- Once warned, the warning is not re-armed until no window shows the
  mismatch, as the windows move with now and a borderline count can
  flip from one cycle to the next.

Tests: 11 kW over two sessions with +/-5 and 10 minute lag, a load gap
(both fail on the old rule), and the re-arm hysteresis.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ed_load check (#5318 review)

A cloud-polled load sensor (GE Cloud caches up to 30 minutes) can be
many minutes behind the charger's energy sensor, so the half hour in
progress reads short and could count as evidence on a correct setup.
Scan from one window back.

Also drop the end-of-history key check, which never fires on the
padded load history, and say instead that missing minutes read as no
increment and are skipped with the empty-load windows; and make the
warning's advice conditional on car_charging_energy being only the car
charger, since the docs still allow other loads in it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
chalfontchubby and others added 2 commits October 11, 2026 11:10
…d-window (#5318 review)

The 2x ratio only protected windows wholly inside a charge session. Where a
session starts part-way through a window, a load sensor that includes the
charger but reports 10-15 minutes late shows only part of that charge, so
the window counted. Two or three Octopus Intelligent dispatches a night were
enough to warn a correctly configured user to turn the switch Off.

A window now counts only if the car energy exceeds twice the load in that
window shifted by every offset up to CAR_ENERGY_LOAD_CHECK_LAG (15) minutes
either way. Running totals keep it to one subtraction per window and shift.
On #5317's debug dump it still finds 7 of the original 8 half hours.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…5318 review)

minute_data() interpolates across a gap inside the history rather than
leaving it flat, so only a stretch before the history or padded over a
reset reads as no load; say so, and that a long outage over a charge can
still count. The load history is only emptied when car_charging_hold is
On as well. Give the test's nested load() helper a docstring.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The warning-only change is consistent with its documented heuristic and has strong boundary-case coverage.

0 open findings

What changed in this PR

Adds a heuristic warning for likely misconfiguration of car_energy_reported_load.

Changes:

  • Detects repeated car-energy/load mismatches using configurable thresholds.
  • Adds one-time warning and re-arm behavior.
  • Documents and comprehensively tests the detection logic.
File Description
docs/​car-charging.md Documents the warning and remediation.
apps/​predbat/​const.py Defines detection thresholds.
apps/​predbat/​fetch.py Implements and invokes mismatch detection.
apps/​predbat/​predbat.py Initializes warning state.
apps/​predbat/​tests/​test_car_energy_reported_load.py Covers detection, lag, gaps, and warning throttling.
apps/​predbat/​unit_test.py Registers the new tests.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

chalfontchubby and others added 5 commits October 12, 2026 10:18
…reported-load-5318

Conflict resolution:
- apps/predbat/predbat.py (PredBat.reset init block): kept this branch's
  new self.car_energy_reported_load_warned = False initialiser, and took
  main's reworded car_slot_owner comment (#5413: the claim covers only
  octopus_ready_time/octopus_charge_limit, not octopus_intelligent_slot).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…plan (#5318)

compare.py re-runs fetch_sensor_data(save=False) once per candidate tariff
(now via run_comparison(), merged from main). The check reads and writes
the live car_energy_reported_load_warned flag, so a tariff config that
turns the switch Off would clear the flag and re-arm the warning every
compare cycle. Gate it on save, as fetch already does for the dispatch
timeline log, and pin the gate in the test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r_energy_reported_load check (#5318)

Replaces the source-text check from the previous commit, which would still
pass if the guarded call moved or its result were ignored. Test 13 now runs
the real fetch_sensor_data() on a fresh PredBat (so nothing it resets leaks
into the shared fixture, #5079), with the history readers stubbed empty:

- save=False with the switch Off and the live flag warned: the check is not
  called and the flag stays set;
- save=True: the check runs once and clears the flag.

With the `if save:` guard removed both assertions fail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…load warning (#5318 review)

Test 13 stubbed both history readers empty, so the check cleared the flag
whatever the switch said and only the call count told pass from fail. It
now feeds a load series that excludes the charger, captures the log, and
runs live cycle (switch On, warns) -> comparison run (save=False, switch
Off) -> next live cycle. Without the gate the comparison run clears the
flag and the next live cycle logs the warning a second time; with it the
warning is logged once. The docstring now says the fetch still sets the
process-wide metrics() gauges rather than claiming nothing leaks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…#5318 review)

The stand-ins only answer for load_today and car_charging_energy, so set
both on the fresh instance instead of relying on coverage/apps.yaml, and
drop ge_cloud_data so the load history cannot take the GE Cloud path
that bypasses minute_data_load().

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request Octopus

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Use car_charging_energy as evidence for Octopus Intelligent dispatches, and warn when car_energy_reported_load looks wrong

2 participants