Skip to content

chore(coordinator): 🔧 parent the sub-devices with via_device_id - #779

Merged
rhammen merged 2 commits into
mainfrom
chore/via-device-id-migration
Aug 30, 2026
Merged

chore(coordinator): 🔧 parent the sub-devices with via_device_id#779
rhammen merged 2 commits into
mainfrom
chore/via-device-id-migration

Conversation

@rhammen

@rhammen rhammen commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator

🔧 What changed

The four logical sub-devices (heating, domestic water, cooling, ventilation) are now parented to the physical heat pump with via_device_id — the device registry id — instead of the deprecated via_device identifier tuple.

The heat pump is registered explicitly in async_setup_entry via a new LuxtronikCoordinator.async_register_devices(), because via_device_id needs the parent to exist in the registry before the children are built. That also keeps the registry write on an explicit, loop-only path instead of hiding it inside get_device(), which is called from an entity constructor.

❓ Why now

Home Assistant 2026.8 added via_device_id and deprecated via_device; 2026.9 removed via_device from the DeviceInfo TypedDict entirely, which makes the old assignment a basedpyright error as soon as homeassistant-stubs reaches 2026.9. The tuple form is also ambiguous now that device identifiers are only unique per config entry.

Supporting both keys behind a runtime capability check was considered and rejected: tests/requirements-dev.txt pins no Home Assistant version and both CI legs install the current release, so a < 2026.8 branch could never be executed — permanently uncovered code in a repo that enforces 100% coverage.

So hacs.json now declares "homeassistant": "2026.8.0". HACS gates per release, reading the hacs.json of the version being downloaded, so anyone on an older core simply keeps 2026.08.29 and stops being offered updates — nothing breaks for them. That release has been marked as the last one supporting HA ≤ 2026.7, and the README now states the requirement for manual installs, which HACS does not gate.

📦 Also in here

  • diagnostics.py: dropped the now-dead "via_device" from TO_REDACT. A registry id is a random hex string; the tuple it replaces embedded the serial number, which is why it was redacted.
  • device_infos is built as one map and assigned in a single step — _async_delete_legacy_devices prunes against it, so a half-filled map would read as "these devices are gone".

✅ Verification

Full gate green: 1205 tests pass, coverage stays at 100%, basedpyright 0 errors (the via_device type error is gone), ruff check + format and codespell clean.

Verified on a live install as well — Home Assistant 2026.9.0b4, Container install, with a device registry that already held the four devices created the old way:

name=WP           ident=..._heatpump        via_device_id=None      serial_number=260126_0477
name=Verw         ident=..._heating         via_device_id=1ee1938e  parent=WP
name=Warmwater    ident=..._domestic_water  via_device_id=1ee1938e  parent=WP
name=Koel         ident=..._cooling         via_device_id=1ee1938e  parent=WP

Four devices, not eight, and the user-assigned names survived — name_by_user lives on the device record, so the existing devices were adopted rather than recreated. The deprecation warnings the integration emitted on 2026.9 are gone.

🧪 Tests

TestCoordinatorSubDeviceParenting covers the parenting id, the absence of the deprecated key on all four sub-devices, the heat pump staying unparented while keeping the serial, adoption of an already-registered heat pump without duplication, and the entry-less coordinator the config flow builds.

Resolves #770 (item 1). Item 2 — DeviceEntry.config_entries in _resolve_write_target — is untouched and still works through Home Assistant's compatibility shim, with runway to 2027.8.

🤖 Generated with Claude Code

- Register the heat pump device explicitly in `async_setup_entry` and link
  heating, domestic water, cooling and ventilation to it by its registry id,
  replacing the deprecated `via_device` identifier tuple
- `via_device` was removed from the `DeviceInfo` TypedDict in Home Assistant
  2026.9, which made the old assignment a type error; the tuple form is also
  ambiguous now that identifiers are only unique per config entry
- Raise the HACS minimum to 2026.8.0, the release that added `via_device_id`.
  Supporting both keys was considered and rejected: the legacy branch could
  never be exercised, since dev and both CI legs install current Home Assistant
- Registration is its own `async_register_devices()` rather than a side effect
  of `get_device()`, keeping the registry write off an entity constructor and
  ahead of the pruning that compares against `device_infos`
- Drop the now-dead `via_device` from the diagnostics redaction set; a registry
  id is a random hex string, unlike the tuple, which embedded the serial

Resolves #770 (item 1)
- Home Assistant requires Python >=3.14.2 from 2026.7 onwards, so the 3.13 job
  resolved back to the newest release that still supports it - HA 2026.2.3,
  six releases behind, and below the 2026.8 minimum this integration now declares
- That combination cannot exist on a user's system: HA >=2026.8 will not install
  on Python 3.13 at all, so the leg tested a configuration nobody can run
- It surfaced now because `via_device_id` is unknown to HA 2026.2, which makes
  the device info match no known type and aborts entity setup - the same failure
  a manual install on an old core would hit, as documented in the README
@github-actions

Copy link
Copy Markdown
Contributor

Code Coverage

Package Line Rate Health
custom_components.luxtronik2 100%
Summary 100% (3675 / 3675)

@rhammen
rhammen merged commit 20788a6 into main Aug 30, 2026
8 checks passed
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.

chore(coordinator): 🔧 adapt to the HA device registry changes before 2027.8

1 participant