Skip to content

Enhance Interface ABC with common connection management#1803

Open
matssun wants to merge 3 commits intoXKNX:mainfrom
matssun:feat/enhance-interface-abstract
Open

Enhance Interface ABC with common connection management#1803
matssun wants to merge 3 commits intoXKNX:mainfrom
matssun:feat/enhance-interface-abstract

Conversation

@matssun
Copy link
Copy Markdown

@matssun matssun commented Feb 25, 2026

Summary

Following @farmio's suggestion in #1802, this PR enhances the Interface ABC to formalize what all concrete implementations already share:

  • Added xknx and cemi_received_callback to __slots__ and type annotations on Interface
  • Added connection_state_changed() concrete method (wraps xknx.connection_manager)
  • Added current_address property (wraps xknx.current_address)
  • Updated _Tunnel and Routing to use these Interface methods instead of direct xknx access
  • Removed duplicate slot declarations from subclasses

Motivation

Every Interface implementation (_Tunnel, Routing) already stores xknx and cemi_received_callback, and uses the same patterns for connection state changes and address management. Moving these to the base class:

  1. Eliminates duplicated code across implementations
  2. Establishes a clear contract for what an Interface provides
  3. Prepares the ABC for custom transport implementations (as discussed in feat: add custom interface injection via ConnectionConfig #1802)

Breaking change

xknx and cemi_received_callback are now declared in Interface.__slots__. Third-party Interface subclasses that redeclare these names in their own __slots__ will need to remove them to avoid a ValueError conflict. This is a one-line fix per subclass.

Changes

File Change
xknx/io/interface.py Added slots, type annotations, connection_state_changed(), current_address property
xknx/io/tunnel.py Removed duplicate xknx/cemi_received_callback slots, use Interface methods
xknx/io/routing.py Removed duplicate xknx/cemi_received_callback slots, use Interface methods

Testing

Pure refactor — no behavior changes. All 2876 existing tests pass with zero regressions.

Formalize attributes and methods that all Interface implementations
already share: xknx/cemi_received_callback slots, connection_state_changed()
method, and current_address property. Update _Tunnel and Routing to use
these Interface methods instead of direct xknx access.

Pure refactor — no behavior changes. Prepares Interface for custom
transport implementations per feedback on XKNX#1802.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings February 25, 2026 21:24
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors the KNX/IP Interface ABC to centralize shared connection-management behavior (xknx/callback storage, connection state updates, and current individual address handling) and updates existing implementations to use the new base-class helpers.

Changes:

  • Extend Interface with additional slots/type annotations plus connection_state_changed() and current_address accessors.
  • Update _Tunnel and Routing to use the new Interface helpers instead of direct xknx access.
  • Remove duplicate slot declarations from tunnel/routing implementations.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
xknx/io/interface.py Adds common connection-management helpers and base slots/type annotations.
xknx/io/tunnel.py Uses Interface.connection_state_changed() and Interface.current_address; removes duplicated slots.
xknx/io/routing.py Uses Interface.connection_state_changed() and Interface.current_address; removes duplicated slots.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@codecov
Copy link
Copy Markdown

codecov bot commented Feb 25, 2026

Codecov Report

❌ Patch coverage is 97.05882% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 97.38%. Comparing base (50fdf8a) to head (243c00f).

Files with missing lines Patch % Lines
xknx/io/interface.py 93.33% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1803      +/-   ##
==========================================
- Coverage   97.38%   97.38%   -0.01%     
==========================================
  Files         160      160              
  Lines       10951    10965      +14     
==========================================
+ Hits        10665    10678      +13     
- Misses        286      287       +1     
Files with missing lines Coverage Δ
xknx/core/connection_manager.py 100.00% <100.00%> (ø)
xknx/io/routing.py 98.46% <100.00%> (ø)
xknx/io/tunnel.py 90.60% <100.00%> (ø)
xknx/io/interface.py 96.55% <93.33%> (-3.45%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@matssun
Copy link
Copy Markdown
Author

matssun commented Feb 27, 2026

Both suggestions look great. We agree to:

  1. Add connection_type: ClassVar[XknxConnectionType] to Interface and simplify connection_state_changed to
    only take state, using self.connection_type internally.
  2. Have ConnectionManager automatically reset connection_type to NOT_CONNECTED when state is DISCONNECTED
    (or any non-CONNECTED state), since the two suggestions need each other for correctness — the simplified
    signature would otherwise forward the subclass's connection_type (e.g., TUNNEL_UDP) to the manager even on
    disconnect.

We'll update the PR accordingly. Thanks for the clear feedback!

- Annotate connection_type as ClassVar[XknxConnectionType] in Interface
  ABC and all subclasses (_Tunnel, UDPTunnel, TCPTunnel, SecureTunnel,
  Routing, RoutingSecure)
- Remove connection_type parameter from Interface.connection_state_changed;
  method now uses self.connection_type internally
- Auto-reset connection_type to NOT_CONNECTED on DISCONNECTED state in
  ConnectionManager, making the invariant explicit and removing reliance
  on callers passing the correct default

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@matssun
Copy link
Copy Markdown
Author

matssun commented Mar 6, 2026

Hello Matthias, just want to check in with you if you have any more comments or want us to refine the PR in any way? Have a nice weekend! /Mats

@farmio
Copy link
Copy Markdown
Member

farmio commented Mar 6, 2026

Hi! Only the one above about the property. Otherwise I think this is good to go.

Co-authored-by: Matthias Alphart <farmio@alphart.net>
# Use the individual address provided by the tunnelling server
self._src_address = connect.crd.individual_address or IndividualAddress(0)
self.xknx.current_address = self._src_address
self.current_address = self._src_address
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this should use the new method now

self.xknx.connection_manager.connection_state_changed(
XknxConnectionState.CONNECTING, self.connection_type
)
self.current_address = self.individual_address
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this should use the new method now

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.

3 participants