"""Manages a connection to the KNX bus.""" from __future__ import annotations from enum import Enum, auto import os from typing import Any from xknx.secure import Keyring from xknx.telegram.address import IndividualAddress, IndividualAddressableType from .const import DEFAULT_MCAST_GRP, DEFAULT_MCAST_PORT from .gateway_scanner import GatewayScanFilter class ConnectionType(Enum): """Enum class for different types of KNX/IP Connections.""" AUTOMATIC = auto() ROUTING = auto() ROUTING_SECURE = auto() TUNNELING = auto() TUNNELING_TCP = auto() TUNNELING_TCP_SECURE = auto() class ConnectionConfig: """ Connection configuration. Handles: * type of connection: * AUTOMATIC for using GatewayScanner for searching and finding KNX/IP devices in the network. * ROUTING use KNX/IP multicast routing. * TUNNELING connect to a specific KNX/IP tunneling device via UDP. * TUNNELING_TCP connect to a specific KNX/IP tunneling v2 device via TCP. * individual address: * AUTOMATIC use a specific tunnel endpoint from a given knxkeys file * ROUTING the individual address used as source address for routing * TCP TUNNELING request a specific tunnel endpoint * SECURE TUNNELING use a specific tunnel endpoint from the knxkeys file * local_ip: Local ip or interface name though which xknx should connect. * gateway_ip: IP or hostname of KNX/IP tunneling device. * gateway_port: Port of KNX/IP tunneling device. * route_back: For UDP TUNNELING connection. The KNXnet/IP Server shall use the IP address and port in the received IP package as the target IP address or port number for the response to the KNXnet/IP Client. * multicast_group: Multicast group for KNXnet/IP routing. * multicast_port: Multicast port for KNXnet/IP routing. * auto_reconnect: Auto reconnect to KNX/IP tunneling device if open connection was lost. * auto_reconnect_wait: Delay in seconds before attempting subsequent reconnects after an initial reconnect attempt fails. * scan_filter: For AUTOMATIC connection, limit scan with the given filter * threaded: Run connection logic in separate thread to avoid concurrency issues in HA * secure_config: KNX Secure config to use """ def __init__( self, *, connection_type: ConnectionType = ConnectionType.AUTOMATIC, individual_address: IndividualAddressableType | None = None, local_ip: str | None = None, local_port: int = 0, gateway_ip: str | None = None, gateway_port: int = DEFAULT_MCAST_PORT, route_back: bool = False, multicast_group: str = DEFAULT_MCAST_GRP, multicast_port: int = DEFAULT_MCAST_PORT, auto_reconnect: bool = True, auto_reconnect_wait: int = 3, scan_filter: GatewayScanFilter | None = None, threaded: bool = False, secure_config: SecureConfig | None = None, ) -> None: """Initialize ConnectionConfig class.""" self.connection_type = connection_type self.individual_address = ( IndividualAddress(individual_address) if individual_address else None ) self.local_ip = local_ip self.local_port = local_port self.gateway_ip = gateway_ip self.gateway_port = gateway_port self.route_back = route_back self.multicast_group = multicast_group self.multicast_port = multicast_port self.auto_reconnect = auto_reconnect self.auto_reconnect_wait = auto_reconnect_wait self.scan_filter = scan_filter or GatewayScanFilter() self.threaded = threaded self.secure_config = secure_config def __eq__(self, other: object) -> bool: """Equality for ConnectionConfig class (used in unit tests).""" return self.__dict__ == other.__dict__ class SecureConfig: """ Secure configuration. Handles: * backbone_key: Key used for KNX Secure Routing in hex representation. * latency_ms: Latency in milliseconds for KNX Secure Routing. * user_id: The user id to use when initializing the secure tunnel. * device_authentication_password: the authentication password to use when connecting to the tunnel. * user_password: the user password for knx secure. * knxkeys_file_path: Full path to the knxkeys file including the file name. * knxkeys_password: Password to decrypt the knxkeys file. * keyring: Already-loaded keyring if it shouldn't be read from the knxkeys file. """ def __init__( self, *, backbone_key: str | None = None, latency_ms: int | None = None, user_id: int | None = None, device_authentication_password: str | None = None, user_password: str | None = None, knxkeys_file_path: str | os.PathLike[Any] | None = None, knxkeys_password: str | None = None, keyring: Keyring | None = None, ) -> None: """Initialize SecureConfig class.""" self.backbone_key = bytes.fromhex(backbone_key) if backbone_key else None self.latency_ms = latency_ms self.user_id = user_id self.device_authentication_password = device_authentication_password self.user_password = user_password self.knxkeys_file_path = knxkeys_file_path self.knxkeys_password = knxkeys_password self.keyring = keyring def __eq__(self, other: object) -> bool: """Equality for SecureConfig class (used in unit tests).""" return self.__dict__ == other.__dict__