Skip to content

feat(config): add num_chargers so a repeated charger is caught rather than silently summed - #4880

Open
chalfontchubby wants to merge 2 commits into
mainfrom
feat/num-chargers-validation
Open

feat(config): add num_chargers so a repeated charger is caught rather than silently summed#4880
chalfontchubby wants to merge 2 commits into
mainfrom
feat/num-chargers-validation

Conversation

@chalfontchubby

@chalfontchubby chalfontchubby commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Written by Claude, posted on behalf of @chalfontchubby.

Fixes #4879

car_charging_power is the one car_charging_* key that is not one entry per car: it lists chargers, and update_car_charging_power() sums them. It sits among five keys that are indexed by num_cars, so a household with two cars sharing one charger naturally lists that charger twice — and Predbat reports double the power it is drawing. The reporter's diagram showed 14140 W against a Zappi reading 7.1 kW.

Why not just detect it

Deduplicating identical entity ids catches the literal [zappi, zappi] case, but not this, which is the shape a careful user is more likely to produce:

car_charging_power:
  - sensor.zappi_id_buzz_charging_power   # template reading the same Zappi
  - sensor.zappi_kia_ev6_charging_power   # template reading the same Zappi

Two distinct entities, one charger. We cannot see through a template sensor to its source, and there is no invariant to check the sum against — car_energy_reported_load exists precisely because the charger may sit outside the house CT clamp. A check that caught one shape and stayed silent on the other would be worse than none: the silence would read as "validated".

So ask instead

num_chargers names the concept Predbat was missing entirely — it models cars and has no notion of chargers at all, which is the root of the confusion. The existing entries validation then compares it against the length of car_charging_power, catching both shapes because it stops trying to infer something invisible.

  • Unset means no check, so no existing apps.yaml changes behaviour.
  • The shipped template sets num_chargers: 1 — the common case, and the one that gets this wrong.
  • Fewer entries than declared is warned but not an error — a charger with no live power sensor is a real, documented setup, so a short list must not force a false count; but an entry deleted by accident under-reports just as quietly as a repeated one over-reports, so it does not pass in silence either. The warning records no arg_error, so a legitimate setup is never left showing "apps.yaml has N errors".

Two supporting changes worth a reviewer's eye

1. entries validation only ever rejected too FEW entries. Extra entries have always been tolerated, and newly rejecting them everywhere would fail working installs. But for a list that is summed rather than indexed, an extra entry inflates the total instead of being ignored. Hence a new entries_exact flag, set only on this key, so every existing key keeps its current behaviour.

2. A latent hole in the item type check. It trims a list to required_entries before validating the items:

if required_entries is not None and len(value) > required_entries:
    value = value[:required_entries]

With a count key that is simply unset, required_entries is 0, so the list was trimmed to nothing and no items were type-checked at all. That silently disabled the existing "a nonsense charger sensor is rejected" behaviour the moment this key gained an entries rule — caught by an existing test, which is how I found it. Guarded with if required_entries instead. The same hole applied to every entries key whenever its count was 0.

Docs

docs/car-charging.md said only the positive case ("one per line, if you have more than one charger"). It now says the negative out loud: this list describes chargers not cars, num_cars has no bearing on it, list each charger once however many cars you have, and two cars sharing a charger is a single entry. Plus the self-check — compare predbat.car_charging_power against the charger's own app; if it reads double, an entry is repeated.

Testing

Four new cases in test_web_power_flow: a duplicated charger against num_chargers: 1 is an error; the same list validates at num_chargers: 2; fewer entries than declared warns without recording an arg_error; and a nonsense sensor is still type-checked with num_chargers unset (the truncation regression above).

./run_all --quick and ./run_all --test debug_cases both pass.

chalfontchubby and others added 2 commits August 31, 2026 12:12
…mmed

car_charging_power is the one car_charging_* key that is not one entry per car:
it lists chargers and update_car_charging_power() sums them. Sitting among five
keys that ARE indexed by num_cars, it reads as per-car, so a household with two
cars sharing one charger naturally lists that charger twice - and Predbat then
reports double the power the charger is drawing (#4879).

We cannot detect this. Deduplicating identical entity ids catches the literal
case but not two template sensors that both read the same charger, and there is
no invariant to check the sum against - car_energy_reported_load exists because
the charger may sit outside the house CT clamp. A check that caught one shape
and stayed silent on the other would be worse than none, since the silence would
read as validated.

So ask instead. num_chargers names the concept Predbat was missing entirely -
it models cars and has no notion of chargers - and lets the existing entries
validation compare it against the length of car_charging_power. Unset means no
check, so no existing apps.yaml changes behaviour; the shipped template sets 1,
which is the common case and the one that gets this wrong.

Two supporting changes:

entries validation only ever rejected too FEW entries. Extra entries have always
been tolerated, and newly rejecting them everywhere would fail working installs -
but for a list that is summed rather than indexed an extra entry inflates the
total instead of being ignored. Hence entries_exact, set only on this key.

The item type check trims a list to required_entries before validating it, so a
count key that is simply unset (0) trimmed the list to nothing and type-checked
no items at all - which silently disabled the existing "a nonsense charger sensor
is rejected" behaviour the moment this key gained an entries rule. Guarded with
"if required_entries" rather than "is not None"; the same latent hole applied to
every entries key whenever its count was 0.

Docs say the missing part out loud: this list describes chargers, not cars, list
each one once however many cars you have, and two cars sharing a charger is a
single entry.

Fixes #4879

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Tolerating a short list silently made num_chargers mean "an upper bound" rather
than "how many chargers I have". A charger with no live power sensor is a real
and documented setup, so a short list must not force a false count - but an
entry deleted by accident under-reports the Car figure just as quietly as a
repeated one over-reports it, which is the whole problem this key exists to stop.

Log it without recording an arg_error, so a legitimate setup is not left showing
"apps.yaml has N errors" forever.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Power flow diagram doubles EV charging draw for 2-car/1-charger setup

1 participant