def connection_config(self) -> ConnectionConfig: """Return the connection_config.""" _conn_type: str = self.config[CONF_KNX_CONNECTION_TYPE] if _conn_type == CONF_KNX_ROUTING: return ConnectionConfig( connection_type=ConnectionType.ROUTING, local_ip=self.config.get(ConnectionSchema.CONF_KNX_LOCAL_IP), auto_reconnect=True, ) if _conn_type == CONF_KNX_TUNNELING: return ConnectionConfig( connection_type=ConnectionType.TUNNELING, gateway_ip=self.config[CONF_HOST], gateway_port=self.config[CONF_PORT], local_ip=self.config.get(ConnectionSchema.CONF_KNX_LOCAL_IP), route_back=self.config.get( ConnectionSchema.CONF_KNX_ROUTE_BACK, False), auto_reconnect=True, ) if _conn_type == CONF_KNX_TUNNELING_TCP: return ConnectionConfig( connection_type=ConnectionType.TUNNELING_TCP, gateway_ip=self.config[CONF_HOST], gateway_port=self.config[CONF_PORT], auto_reconnect=True, ) return ConnectionConfig(auto_reconnect=True)
def test_config_connection(self): """Test connection section from config file.""" # Default connection setting from xknx.yaml (auto:) self.assertEqual( TestConfig.xknx.connection_config, ConnectionConfig(connection_type=ConnectionType.AUTOMATIC), ) # Replaces setting from xknx.yaml test_configs = [ ( """ connection: tunneling: local_ip: '192.168.1.2' gateway_ip: 192.168.1.15 gateway_port: 6000 """, ConnectionConfig( connection_type=ConnectionType.TUNNELING, local_ip="192.168.1.2", gateway_ip="192.168.1.15", gateway_port=6000, ), ), ( """ connection: tunneling: gateway_ip: '192.168.1.2' """, ConnectionConfig( connection_type=ConnectionType.TUNNELING, gateway_ip="192.168.1.2" ), ), ( """ connection: routing: local_ip: '192.168.1.2' """, ConnectionConfig( connection_type=ConnectionType.ROUTING, local_ip="192.168.1.2" ), ), ( """ connection: routing: """, ConnectionConfig(connection_type=ConnectionType.ROUTING), ), ] for yaml_string, expected_conn in test_configs: config = yaml.safe_load(yaml_string) ConfigV1(TestConfig.xknx).parse_connection(config) self.assertEqual(TestConfig.xknx.connection_config, expected_conn)
def connection_config(self) -> ConnectionConfig: """Return the connection_config.""" _conn_type: str = self.entry.data[CONF_KNX_CONNECTION_TYPE] if _conn_type == CONF_KNX_ROUTING: return ConnectionConfig( connection_type=ConnectionType.ROUTING, local_ip=self.entry.data.get(CONF_KNX_LOCAL_IP), auto_reconnect=True, threaded=True, ) if _conn_type == CONF_KNX_TUNNELING: return ConnectionConfig( connection_type=ConnectionType.TUNNELING, gateway_ip=self.entry.data[CONF_HOST], gateway_port=self.entry.data[CONF_PORT], local_ip=self.entry.data.get(CONF_KNX_LOCAL_IP), route_back=self.entry.data.get(CONF_KNX_ROUTE_BACK, False), auto_reconnect=True, threaded=True, ) if _conn_type == CONF_KNX_TUNNELING_TCP: return ConnectionConfig( connection_type=ConnectionType.TUNNELING_TCP, gateway_ip=self.entry.data[CONF_HOST], gateway_port=self.entry.data[CONF_PORT], auto_reconnect=True, threaded=True, ) if _conn_type == CONF_KNX_TUNNELING_TCP_SECURE: knxkeys_file: str | None = (self.hass.config.path( STORAGE_DIR, self.entry.data[CONF_KNX_KNXKEY_FILENAME], ) if self.entry.data.get(CONF_KNX_KNXKEY_FILENAME) is not None else None) return ConnectionConfig( connection_type=ConnectionType.TUNNELING_TCP_SECURE, gateway_ip=self.entry.data[CONF_HOST], gateway_port=self.entry.data[CONF_PORT], secure_config=SecureConfig( user_id=self.entry.data.get(CONF_KNX_SECURE_USER_ID), user_password=self.entry.data.get( CONF_KNX_SECURE_USER_PASSWORD), device_authentication_password=self.entry.data.get( CONF_KNX_SECURE_DEVICE_AUTHENTICATION), knxkeys_password=self.entry.data.get( CONF_KNX_KNXKEY_PASSWORD), knxkeys_file_path=knxkeys_file, ), auto_reconnect=True, threaded=True, ) return ConnectionConfig( auto_reconnect=True, threaded=True, )
def _parse_connection_prefs(self, conn_type: ConnectionType, prefs) -> None: connection_config = ConnectionConfig(connection_type=conn_type) if hasattr(prefs, '__iter__'): for pref, value in prefs.items(): if pref == "gateway_ip": connection_config.gateway_ip = value elif pref == "gateway_port": connection_config.gateway_port = value elif pref == "local_ip": connection_config.local_ip = value self.xknx.connection_config = connection_config
async def start(self, state_updater=False, daemon_mode=False, connection_config=None): """Start XKNX module. Connect to KNX/IP devices and start state updater.""" if connection_config is None: if self.connection_config is None: connection_config = ConnectionConfig() else: connection_config = self.connection_config self.knxip_interface = KNXIPInterface( self, connection_config=connection_config) self.logger.info('XKNX v%s starting %s connection to KNX bus.', VERSION, connection_config.connection_type.name.lower()) await self.knxip_interface.start() await self.telegram_queue.start() if state_updater: from xknx.core import StateUpdater self.state_updater = StateUpdater(self) await self.state_updater.start() if daemon_mode: await self.loop_until_sigint() self.started = True
async def test_threaded_connection(self): """Test starting threaded connection.""" # pylint: disable=attribute-defined-outside-init self.main_thread = threading.get_ident() xknx = XKNX(connection_config=ConnectionConfig(threaded=True)) async def assert_main_thread(*args, **kwargs): """Test callback is done by main thread.""" assert self.main_thread == threading.get_ident() xknx.connection_manager.register_connection_state_changed_cb( assert_main_thread) async def set_connected(): """Set connected state.""" await xknx.connection_manager.connection_state_changed( XknxConnectionState.CONNECTED) assert self.main_thread != threading.get_ident() with patch("xknx.io.KNXIPInterface._start", side_effect=set_connected): await xknx.start() # wait for side_effect to finish await asyncio.wait_for(xknx.connection_manager.connected.wait(), timeout=1) await xknx.stop()
async def test_start_udp_tunnel_connection(self): """Test starting UDP tunnel connection.""" # without gateway_ip automatic is called gateway_ip = "127.0.0.2" connection_config = ConnectionConfig( connection_type=ConnectionType.TUNNELING, gateway_ip=gateway_ip) with patch("xknx.io.KNXIPInterface._start_tunnelling_udp" ) as start_tunnelling_udp: interface = knx_interface_factory(self.xknx, connection_config) await interface.start() start_tunnelling_udp.assert_called_once_with( gateway_ip=gateway_ip, gateway_port=3671, ) with patch("xknx.io.tunnel.UDPTunnel.connect") as connect_udp: interface = knx_interface_factory(self.xknx, connection_config) await interface.start() assert isinstance(interface._interface, UDPTunnel) assert interface._interface.local_ip == "127.0.0.1" assert interface._interface.local_port == 0 assert interface._interface.gateway_ip == gateway_ip assert interface._interface.gateway_port == 3671 assert interface._interface.auto_reconnect assert interface._interface.auto_reconnect_wait == 3 assert interface._interface.route_back is False assert ( # pylint: disable=comparison-with-callable interface._interface.telegram_received_callback == interface.telegram_received) connect_udp.assert_called_once_with()
async def task(client, cfg, server: KNXserver, evt=None, local_ip=None, initial=False): # pylint: disable=unused-argument cfg = combine_dict(server.value_or({}, Mapping), cfg["server_default"]) add = {} if local_ip is not None: add["local_ip"] = local_ip try: ccfg = ConnectionConfig(connection_type=ConnectionType.TUNNELING, gateway_ip=cfg["host"], gateway_port=cfg.get("port", 3671), **add) async with xknx.XKNX().run(connection_config=ccfg) as srv: await server.set_server(srv, initial=initial) if evt is not None: evt.set() while True: await anyio.sleep(99999) except TimeoutError: raise except socket.error as e: # this would eat TimeoutError raise ClientConnectionError(cfg["host"], cfg["port"]) from e
def connection_config_routing(self): """Return the connection_config if routing is configured.""" from xknx.io import ConnectionConfig, ConnectionType local_ip = \ self.config[DOMAIN][CONF_KNX_ROUTING].get(CONF_KNX_LOCAL_IP) return ConnectionConfig(connection_type=ConnectionType.ROUTING, local_ip=local_ip)
async def test_threaded_send_telegram(self): """Test sending telegram with threaded connection.""" # pylint: disable=attribute-defined-outside-init self.main_thread = threading.get_ident() def assert_thread(*args, **kwargs): """Test threaded connection.""" assert self.main_thread != threading.get_ident() return DEFAULT # to not disable `return_value` of send_telegram_mock local_ip = "127.0.0.1" # set local_ip to avoid gateway scanner; use routing as it is the simplest mode connection_config = ConnectionConfig( connection_type=ConnectionType.ROUTING, local_ip=local_ip, threaded=True) telegram_mock = Mock() with patch("xknx.io.routing.Routing.connect", side_effect=assert_thread) as connect_routing_mock, patch( "xknx.io.routing.Routing.send_telegram", side_effect=assert_thread, return_value="test", ) as send_telegram_mock, patch( "xknx.io.routing.Routing.disconnect", side_effect=assert_thread) as disconnect_routing_mock: interface = knx_interface_factory(self.xknx, connection_config) await interface.start() connect_routing_mock.assert_called_once_with() assert await interface.send_telegram(telegram_mock) == "test" send_telegram_mock.assert_called_once_with(telegram_mock) await interface.stop() disconnect_routing_mock.assert_called_once_with() assert interface._interface is None
async def main(): """Connect to KNX/IP device and create a weather device and read its sensors.""" xknx = XKNX() await xknx.start(connection_config=ConnectionConfig( connection_type=ConnectionType.TUNNELING, local_ip="192.168.0.50", gateway_ip="192.168.0.100", )) weather = Weather( xknx, "Home", group_address_temperature="7/0/1", group_address_brightness_south="7/0/5", group_address_brightness_east="7/0/4", group_address_brightness_west="7/0/3", group_address_wind_speed="7/0/2", group_address_day_night="7/0/7", group_address_rain_alarm="7/0/0", ) await weather.sync(wait_for_result=True) print(weather.max_brightness) print(weather.ha_current_state()) print(weather) await xknx.stop()
def connection_config(self) -> ConnectionConfig: """Return the connection_config.""" if CONF_KNX_TUNNELING in self.config[DOMAIN]: return self.connection_config_tunneling() if CONF_KNX_ROUTING in self.config[DOMAIN]: return self.connection_config_routing() return ConnectionConfig(auto_reconnect=True)
async def main(): connection_config = ConnectionConfig( connection_type=ConnectionType.TUNNELING, gateway_ip="10.0.0.197", gateway_port=3671, local_ip="10.0.0.70") xknx = XKNX(connection_config=connection_config) await xknx.start() print(len(xknx.devices)) for device in xknx.devices: print(device) print("Start done") light = Light(xknx, name ='Lamp Pieter', group_address_switch='0/2/18') print(light) await light.set_off() TempSensor = Sensor(xknx, 'TempSensor Bureel Pieter', group_address_state='2/2/11', value_type='temperature') await TempSensor.sync() print(TempSensor) print(TempSensor.resolve_state()) print(TempSensor.unit_of_measurement()) print(TempSensor.sensor_value.value) await xknx.stop()
def connection_config_routing(self): """Return the connection_config if routing is configured.""" local_ip = self.config[DOMAIN][CONF_KNX_ROUTING].get( ConnectionSchema.CONF_KNX_LOCAL_IP ) return ConnectionConfig( connection_type=ConnectionType.ROUTING, local_ip=local_ip )
def _parse_connection_prefs(self, conn_type: ConnectionType, prefs) -> None: connection_config = ConnectionConfig(connection_type=conn_type) if hasattr(prefs, '__iter__'): for pref, value in prefs.items(): try: if pref == "gateway_ip": connection_config.gateway_ip = value elif pref == "gateway_port": connection_config.gateway_port = value elif pref == "local_ip": connection_config.local_ip = value except XKNXException as ex: self.xknx.logger.error( "Error while reading config file: Could not parse %s: %s", pref, ex) self.xknx.connection_config = connection_config
def connection_config(self): """Return the connection_config.""" if CONF_KNX_TUNNELING in self.config[DOMAIN]: return self.connection_config_tunneling() if CONF_KNX_ROUTING in self.config[DOMAIN]: return self.connection_config_routing() # config from xknx.yaml always has priority later on return ConnectionConfig(auto_reconnect=True)
def connection_config_routing(self): """Return the connection_config if routing is configured.""" local_ip = None # all configuration values are optional if self.config[DOMAIN][CONF_KNX_ROUTING] is not None: local_ip = self.config[DOMAIN][CONF_KNX_ROUTING].get( ConnectionSchema.CONF_KNX_LOCAL_IP) return ConnectionConfig(connection_type=ConnectionType.ROUTING, local_ip=local_ip)
def __init__( self, own_address: str | IndividualAddress = DEFAULT_ADDRESS, address_format: GroupAddressType = GroupAddressType.LONG, telegram_received_cb: Callable[[Telegram], Awaitable[None]] | None = None, device_updated_cb: Callable[[Device], Awaitable[None]] | None = None, connection_state_changed_cb: Callable[[XknxConnectionState], Awaitable[None]] | None = None, rate_limit: int = DEFAULT_RATE_LIMIT, multicast_group: str = DEFAULT_MCAST_GRP, multicast_port: int = DEFAULT_MCAST_PORT, log_directory: str | None = None, state_updater: TrackerOptionType = False, daemon_mode: bool = False, connection_config: ConnectionConfig = ConnectionConfig(), ) -> None: """Initialize XKNX class.""" self.connection_manager = ConnectionManager() self.devices = Devices() self.knxip_interface = knx_interface_factory( self, connection_config=connection_config) self.management = Management(self) self.telegrams: asyncio.Queue[Telegram | None] = asyncio.Queue() self.telegram_queue = TelegramQueue(self) self.state_updater = StateUpdater(self, default_tracker_option=state_updater) self.task_registry = TaskRegistry(self) self.current_address = IndividualAddress(0) self.daemon_mode = daemon_mode self.multicast_group = multicast_group self.multicast_port = multicast_port self.own_address = IndividualAddress(own_address) self.rate_limit = rate_limit self.sigint_received = asyncio.Event() self.started = asyncio.Event() self.version = VERSION GroupAddress.address_format = address_format # for global string representation if log_directory is not None: self.setup_logging(log_directory) if telegram_received_cb is not None: self.telegram_queue.register_telegram_received_cb( telegram_received_cb) if device_updated_cb is not None: self.devices.register_device_updated_cb(device_updated_cb) if connection_state_changed_cb is not None: self.connection_manager.register_connection_state_changed_cb( connection_state_changed_cb)
async def test_invalid_user_password(self): """Test ip secure.""" gateway_ip = "192.168.1.1" connection_config = ConnectionConfig( connection_type=ConnectionType.TUNNELING_TCP_SECURE, gateway_ip=gateway_ip, secure_config=SecureConfig(user_id=1, ), ) with pytest.raises(InvalidSecureConfiguration): interface = knx_interface_factory(self.xknx, connection_config) await interface.start()
async def run(self): ccfg = ConnectionConfig( connection_type=ConnectionType.TUNNELING, gateway_ip="127.0.0.1", gateway_port=TCP_PORT, ) async with self._daemon() as server: async with xknx.XKNX().run(connection_config=ccfg) as client: self._server = server self._client = client yield self
def connection_config_tunneling(self): """Return the connection_config if tunneling is configured.""" gateway_ip = self.config[DOMAIN][CONF_KNX_TUNNELING].get(CONF_HOST) gateway_port = self.config[DOMAIN][CONF_KNX_TUNNELING].get(CONF_PORT) local_ip = self.config[DOMAIN][CONF_KNX_TUNNELING].get(CONF_KNX_LOCAL_IP) if gateway_port is None: gateway_port = DEFAULT_MCAST_PORT return ConnectionConfig( connection_type=ConnectionType.TUNNELING, gateway_ip=gateway_ip, gateway_port=gateway_port, local_ip=local_ip, )
def connection_config_tunneling(self): """Return the connection_config if tunneling is configured.""" gateway_ip = self.config[DOMAIN][CONF_KNX_TUNNELING][CONF_HOST] gateway_port = self.config[DOMAIN][CONF_KNX_TUNNELING][CONF_PORT] local_ip = self.config[DOMAIN][CONF_KNX_TUNNELING].get( ConnectionSchema.CONF_KNX_LOCAL_IP) return ConnectionConfig( connection_type=ConnectionType.TUNNELING, gateway_ip=gateway_ip, gateway_port=gateway_port, local_ip=local_ip, auto_reconnect=True, )
async def test_invalid_user_id_secure_error(self): """Test ip secure.""" gateway_ip = "192.168.1.1" knxkeys_file = os.path.join(os.path.dirname(__file__), "resources/testcase.knxkeys") connection_config = ConnectionConfig( connection_type=ConnectionType.TUNNELING_TCP_SECURE, gateway_ip=gateway_ip, secure_config=SecureConfig(user_id=12, knxkeys_file_path=knxkeys_file, knxkeys_password="******"), ) with pytest.raises(InterfaceWithUserIdNotFound): interface = knx_interface_factory(self.xknx, connection_config) await interface.start()
async def test_xknx_start_and_stop_with_dedicated_connection_config( self, start_mock ): """Test xknx start and stop with connection config.""" connection_config = ConnectionConfig(connection_type=ConnectionType.TUNNELING) xknx = XKNX(connection_config=connection_config) await xknx.start() start_mock.assert_called_once() assert xknx.knxip_interface.connection_config == connection_config await xknx.stop() assert xknx.knxip_interface._interface is None assert xknx.telegram_queue._consumer_task.done() assert not xknx.state_updater.started
async def test_threaded_connection(self): """Test starting threaded connection.""" # pylint: disable=attribute-defined-outside-init self.main_thread = threading.get_ident() def assert_thread(*args, **kwargs): """Test threaded connection.""" assert self.main_thread != threading.get_ident() connection_config = ConnectionConfig(threaded=True) assert connection_config.connection_type == ConnectionType.AUTOMATIC with patch("xknx.io.KNXIPInterface._start_automatic", side_effect=assert_thread) as start_automatic_mock: interface = knx_interface_factory(self.xknx, connection_config) await interface.start() start_automatic_mock.assert_called_once_with()
def __init__( self, config: Optional[str] = None, own_address: Union[str, IndividualAddress] = DEFAULT_ADDRESS, address_format: GroupAddressType = GroupAddressType.LONG, telegram_received_cb: Optional[Callable[[Telegram], Awaitable[None]]] = None, device_updated_cb: Optional[Callable[[Device], Awaitable[None]]] = None, rate_limit: int = DEFAULT_RATE_LIMIT, multicast_group: str = DEFAULT_MCAST_GRP, multicast_port: int = DEFAULT_MCAST_PORT, log_directory: Optional[str] = None, state_updater: bool = False, daemon_mode: bool = False, connection_config: ConnectionConfig = ConnectionConfig(), ) -> None: """Initialize XKNX class.""" # pylint: disable=too-many-arguments self.devices = Devices() self.telegrams: asyncio.Queue[Optional[Telegram]] = asyncio.Queue() self.sigint_received = asyncio.Event() self.telegram_queue = TelegramQueue(self) self.state_updater = StateUpdater(self) self.knxip_interface: Optional[KNXIPInterface] = None self.started = asyncio.Event() self.connected = asyncio.Event() self.address_format = address_format self.own_address = IndividualAddress(own_address) self.rate_limit = rate_limit self.multicast_group = multicast_group self.multicast_port = multicast_port self.connection_config = connection_config self.start_state_updater = state_updater self.daemon_mode = daemon_mode self.version = VERSION if log_directory is not None: self.setup_logging(log_directory) if config is not None: Config(self).read(config) if telegram_received_cb is not None: self.telegram_queue.register_telegram_received_cb(telegram_received_cb) if device_updated_cb is not None: self.devices.register_device_updated_cb(device_updated_cb)
def __init__( self, config=None, own_address=DEFAULT_ADDRESS, address_format=GroupAddressType.LONG, telegram_received_cb=None, device_updated_cb=None, rate_limit=DEFAULT_RATE_LIMIT, multicast_group=DEFAULT_MCAST_GRP, multicast_port=DEFAULT_MCAST_PORT, log_directory=None, state_updater=False, daemon_mode=False, connection_config=ConnectionConfig(), ): """Initialize XKNX class.""" # pylint: disable=too-many-arguments self.devices = Devices() self.telegrams = asyncio.Queue() self.sigint_received = asyncio.Event() self.telegram_queue = TelegramQueue(self) self.state_updater = StateUpdater(self) self.knxip_interface = None self.started = asyncio.Event() self.address_format = address_format self.own_address = PhysicalAddress(own_address) self.rate_limit = rate_limit self.multicast_group = multicast_group self.multicast_port = multicast_port self.connection_config = connection_config self.start_state_updater = state_updater self.daemon_mode = daemon_mode self.version = VERSION if log_directory is not None: self.setup_logging(log_directory) if config is not None: Config(self).read(config) if telegram_received_cb is not None: self.telegram_queue.register_telegram_received_cb( telegram_received_cb) if device_updated_cb is not None: self.devices.register_device_updated_cb(device_updated_cb)
def test_xknx_start_and_stop_with_dedicated_connection_config( self, start_mock): """Test xknx start and stop with connection config.""" xknx = XKNX() connection_config = ConnectionConfig( connection_type=ConnectionType.TUNNELING) xknx.connection_config = connection_config self.loop.run_until_complete(xknx.start()) start_mock.assert_called_once() self.assertEqual(xknx.knxip_interface.connection_config, connection_config) self.loop.run_until_complete(xknx.stop()) self.assertIsNone(xknx.knxip_interface) self.assertTrue(xknx.telegram_queue._consumer_task.done()) self.assertFalse(xknx.state_updater.started)
def start(self, state_updater=False, daemon_mode=False, connection_config=ConnectionConfig()): """Start XKNX module. Connect to KNX/IP devices and start state updater.""" self.knxip_interface = KNXIPInterface( self, connection_config=connection_config) yield from self.knxip_interface.start() yield from self.telegram_queue.start() if state_updater: from xknx.core import StateUpdater self.state_updater = StateUpdater(self) yield from self.state_updater.start() if daemon_mode: yield from self.loop_until_sigint() self.started = True
async def test_start_routing_connection(self): """Test starting routing connection.""" local_ip = "127.0.0.1" # set local_ip to avoid gateway scanner connection_config = ConnectionConfig( connection_type=ConnectionType.ROUTING, local_ip=local_ip) with patch("xknx.io.KNXIPInterface._start_routing") as start_routing: interface = knx_interface_factory(self.xknx, connection_config) await interface.start() start_routing.assert_called_once_with(local_ip=local_ip, ) with patch("xknx.io.routing.Routing.connect") as connect_routing: interface = knx_interface_factory(self.xknx, connection_config) await interface.start() assert isinstance(interface._interface, Routing) assert interface._interface.local_ip == local_ip assert ( # pylint: disable=comparison-with-callable interface._interface.telegram_received_callback == interface.telegram_received) connect_routing.assert_called_once_with()