Skip to content

fix(config_flow): 🐛 explain which entry an already-configured abort collided with - #726

Merged
rhammen merged 2 commits into
mainfrom
fix/already-configured-abort-diagnostics
Aug 5, 2026
Merged

fix(config_flow): 🐛 explain which entry an already-configured abort collided with#726
rhammen merged 2 commits into
mainfrom
fix/already-configured-abort-diagnostics

Conversation

@rhammen

@rhammen rhammen commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

🐛 Problem

Reported in #724: with three controllers behind one hostname on different port forwards, adding a second one aborts with "This device is already configured.", and the debug log says:

Device already configured: name1.mooo.com

That message names the host, but the match is actually on the unique_id — which is the heat pump's serial number (ID_WP_SerienNummer_DATUM/_HEX), with host and port playing no part. The reporter went looking for a duplicate host in .storage, found nothing, and had no way to see what actually collided.

🔍 What this changes

Diagnostics only — the identity rule is unchanged. The unique_id stays the serial number, and two endpoints reporting the same serial still cannot both be configured. That is the correct invariant: the serial is the device identity, so a second endpoint with a known serial means both addresses reach the same controller (typically a duplicate port forward), not a second pump. Allowing both would mean two config entries polling one controller and two sets of entities contending over every write.

What changes is that the abort now says so:

WARNING  Device at name1.mooo.com:8450 reports serial '230924_0271', which is already
         configured as 'Luxtronik @ name1.mooo.com:8452' (name1.mooo.com:8452). Both
         addresses reach the same heat pump - check for a duplicate port forward if
         you expected two separate units

and the user sees the same in the UI instead of the bare "This device is already configured."

🛠️ Implementation

  • _set_unique_id_or_abort splits the serial lookup out of the unique-id check. Aside from enabling the above, this fixes the LuxtronikSerialNumberError handler having been reachable only through the evaluation order of coordinator.unique_id inside the shared try.
  • New _abort_already_configured resolves the conflicting config entry and aborts with a new already_configured_serial reason carrying {host}, {serial}, {existing_host} and {existing_title}.
  • When no stored entry matches the serial — the conflict came from an in-progress flow — it falls back to the generic already_configured.
  • The generic already_configured string is left placeholder-free, since the DHCP path aborts through core's _abort_if_unique_id_configured and would have nothing to substitute.

🌍 Translations

already_configured_serial added to en, de, nl, cs, pl, all with the same four placeholders.

✅ Verification

  • 866 tests pass; coverage stays at 100% (config_flow.py 205/205).
  • ruff check clean, ruff format --check clean, basedpyright 0 errors, codespell clean.
  • .github/scripts/check_translation_coverage.py: complete coverage, no placeholder drift across locales.

⚠️ Note on #724

This does not by itself close #724. It makes the cause visible, but which outcome is correct depends on something only the reporter can confirm: whether :8450 and :8452 reach two physically distinct units. If they do — two units with identical factory serials — they will still be blocked and we would need a separate decision about identity. If, as the evidence suggests, both forwards reach one controller, this PR turns a confusing dead end into an actionable message.

🤖 Generated with Claude Code

rhammen and others added 2 commits August 6, 2026 00:14
…ollided with

- Split the serial lookup out of the unique-id check in
  `_set_unique_id_or_abort`, so the abort log names the real cause instead
  of the host: the previous message ("Device already configured: <host>")
  pointed at the host while the match was actually on the serial-derived
  unique_id, sending users hunting for a duplicate host in .storage.
- Add `_abort_already_configured`, which resolves the conflicting config
  entry and reports it via a new `already_configured_serial` abort reason
  with host/serial/existing entry placeholders. Since the unique_id is the
  heat pump's serial number, a second endpoint aborting here means both
  addresses reach the same controller - typically a duplicate port forward.
- Fall back to the generic `already_configured` reason when no stored entry
  matches the serial (the conflict then came from an in-progress flow).
- Add the new string to en/de/nl/cs/pl; the generic `already_configured`
  string stays placeholder-free for the core-raised DHCP abort path.
- The `LuxtronikSerialNumberError` handler was only reachable via the
  evaluation order of `coordinator.unique_id` inside the shared `try`; it
  now guards that lookup explicitly.

Refs #724

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…nfigured_serial

- Hassfest rejects placeholders wrapped in single quotes ("the string should
  not contain placeholders inside single quotes"), which failed CI on
  '{existing_title}'.
- Drop the surrounding quotes in en/de/nl/cs/pl; the entry title still reads
  clearly followed by its address in parentheses.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Code Coverage

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

@rhammen
rhammen merged commit 4799869 into main Aug 5, 2026
9 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.

Add hub fails with "This device is already configured." if device Serial Number overlapping with already registered device

1 participant