Skip to content

fix(chargers): isolate car plans and preserve composed measurements - #4934

Closed
mgazza wants to merge 2 commits into
feat/charger-registryfrom
review/4928-fixes
Closed

fix(chargers): isolate car plans and preserve composed measurements#4934
mgazza wants to merge 2 commits into
feat/charger-registryfrom
review/4928-fixes

Conversation

@mgazza

@mgazza mgazza commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

A charger moved to a different slot by #4928 can consume the previous occupant's published plan. Track the registry allocation version from configuration fetch through plan publication, and make all four charger controls wait for a plan built from the current mapping. Also keep each car's published window list separate: the previous list was shared across loop iterations, so later cars inherited earlier cars' windows.

Fix two measurement regressions: Ohme retains its energy and power contribution when another component registers first or discovery repeats; legacy and discovered measurements of the same charger are counted once. Matching uses the existing exact-entity and bounded manufacturer-serial rules, and legacy measurements are restored when discovery releases them.

Validation:

  • The full unit_test.py --quick suite passed (four slow tests skipped).
  • All seven affected component/registry suites passed, including 62 registry regressions and 97 Ohme tests.
  • All pre-commit hooks for changed files passed.
  • Both energy regressions were reproduced against the original PR. New tests cover each control loop waiting after reassignment and rejecting a plan published for an older allocation.

Slot numbering still follows the ordering documented in #4928; adding a charger may require adjusting per-car settings. This follow-up targets feat/charger-registry, keeping the review fixes separate from the original feature.

Predbat has no charger concept - only a flat, index-keyed list of "cars"
(car_n, num_cars) where each index is really a car-charger pair. Five
integrations autoconfigure into the same shared args, and they collide.

Two distinct defects:

1. List replacement. Gateway, GivEnergy Cloud, Ohme and myenergi each
   assign their OWN discovered list to car_charging_planned/_energy/
   _power. The last component to run wins; every earlier component's
   chargers vanish from the plan.

2. num_cars is a max, not a sum. Even the raise-only discipline in
   gecloud cannot compose: one GivEnergy charger plus one Ohme charger
   yields num_cars=1, and both claim slot 0.

This adds apps/predbat/charger_registry.py. Components stop assigning
car_charging_* directly and call register_chargers(source, entries) - an
atomic, idempotent per-source replace. The registry keys chargers on
(source, device_id), allocates a slot each, and materialises the flat
args once.

Crucially it also exposes slot_for(source, device_id). Every control
loop previously assumed its own charger was car 0, or that its Nth
charger was car N (myenergi's controlled_zappis docstring stated the
invariant outright). Allocating slots across components without fixing
those loops would drive a physical charger from another car's plan, so
discovery and control are migrated together for all four components.

Behaviour changes worth calling out in review:

- num_cars is no longer raise-only. It is derived from registered
  chargers and floored at any value an external source claims, via a new
  set_external_num_cars() that Octopus and Kraken use for their IOG car
  counts. It can decrease when a charger source empties.
- Charger N is no longer car N. Slots are allocated across all
  components by (source, device_id) sort, legacy slots first. Adding a
  source renumbers later chargers, and per-car apps.yaml settings are
  slot-addressed, so they follow the position.
- Hand-written car_charging_* config now composes with autodiscovery
  instead of being overwritten: it is pre-registered as legacy slots,
  preserved verbatim (interior holes included), and discovered chargers
  append after it. Installs on the stock template are unchanged - an
  unresolved "re:" entry is treated as unconfigured.
- set_arg_auto's apps.yaml-override note no longer fires for charger
  keys, because config is merged rather than discarded.
- gateway_evc_control without gateway_evc_automatic now warns once
  rather than silently doing nothing.
- EV commands carry charge_point_id. Older gateway firmware falls back
  to firstConnected(), so it degrades to the previous behaviour.

Known limitations, documented rather than fixed here: the gateway's
6-character entity slug is not collision-proof, so two charge points
with matching slug tails share an entity namespace; alphaess still
writes car_charging_energy/_power directly and is not migrated;
component restart leaves stale registrations, as it left stale args
before.

Tests: 57 registry tests registered in unit_test.py's TEST_REGISTRY so
they run under --quick, plus regressions in the ohme, myenergi,
ge_cloud, gateway, kraken and octopus suites.
@mgazza
mgazza force-pushed the feat/charger-registry branch from 0b7720e to 569f325 Compare September 5, 2026 00:24
@mgazza

mgazza commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator Author

Superseded by #4928 — please close.

These fixes are now folded into #4928 (569f3255) rather than stacked on it. #4928 hadn't been reviewed yet, so keeping them separate would have meant offering a two-deep stack whose base had four known defects — a worse review surface, not a better one.

Everything here is in #4928: the registry allocation version carried from configuration fetch through to plan publication so no control loop acts on a plan built for an older mapping, the per-car published window list isolation, Ohme's retained energy and power contribution, and the legacy/discovered measurement dedupe — with their regressions. The branch is also rebased onto current main.

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.

1 participant