def create_knxipframe(self) -> KNXIPFrame: """Create KNX/IP Frame object to be sent to device.""" # use the same HPAI for control_endpoint and data_endpoint connect_request = ConnectRequest( request_type=ConnectRequestType.TUNNEL_CONNECTION, control_endpoint=self.local_hpai, data_endpoint=self.local_hpai, ) return KNXIPFrame.init_from_body(connect_request)
def test_connect(self): """Test connecting from KNX bus.""" xknx = XKNX() udp_client = UDPClient(xknx, ("192.168.1.1", 0), ("192.168.1.2", 1234)) connect = Connect(xknx, udp_client, route_back=False) connect.timeout_in_seconds = 0 self.assertEqual(connect.awaited_response_class, ConnectResponse) # Expected KNX/IP-Frame: exp_knxipframe = KNXIPFrame.init_from_body( ConnectRequest( xknx, request_type=ConnectRequestType.TUNNEL_CONNECTION, control_endpoint=HPAI(ip_addr="192.168.1.3", port=4321), data_endpoint=HPAI(ip_addr="192.168.1.3", port=4321), ) ) with patch("xknx.io.UDPClient.send") as mock_udp_send, patch( "xknx.io.UDPClient.getsockname" ) as mock_udp_getsockname: mock_udp_getsockname.return_value = ("192.168.1.3", 4321) self.loop.run_until_complete(connect.start()) mock_udp_send.assert_called_with(exp_knxipframe) # Response KNX/IP-Frame with wrong type wrong_knxipframe = KNXIPFrame(xknx) wrong_knxipframe.init(KNXIPServiceType.CONNECTIONSTATE_REQUEST) with patch("logging.Logger.warning") as mock_warning: connect.response_rec_callback(wrong_knxipframe, None) mock_warning.assert_called_with("Could not understand knxipframe") # Response KNX/IP-Frame with error: err_knxipframe = KNXIPFrame(xknx) err_knxipframe.init(KNXIPServiceType.CONNECT_RESPONSE) err_knxipframe.body.status_code = ErrorCode.E_CONNECTION_ID with patch("logging.Logger.debug") as mock_warning: connect.response_rec_callback(err_knxipframe, None) mock_warning.assert_called_with( "Error: KNX bus responded to request of type '%s' with error in '%s': %s", type(connect).__name__, type(err_knxipframe.body).__name__, ErrorCode.E_CONNECTION_ID, ) # Correct Response KNX/IP-Frame: res_knxipframe = KNXIPFrame(xknx) res_knxipframe.init(KNXIPServiceType.CONNECT_RESPONSE) res_knxipframe.body.communication_channel = 23 res_knxipframe.body.identifier = 7 connect.response_rec_callback(res_knxipframe, None) self.assertTrue(connect.success) self.assertEqual(connect.communication_channel, 23) self.assertEqual(connect.identifier, 7)
async def test_connect(self): """Test connecting from KNX bus.""" udp_transport = UDPTransport(("192.168.1.1", 0), ("192.168.1.2", 1234)) local_hpai = HPAI(ip_addr="192.168.1.3", port=4321) connect = Connect(udp_transport, local_hpai=local_hpai) connect.timeout_in_seconds = 0 assert connect.awaited_response_class == ConnectResponse # Expected KNX/IP-Frame: exp_knxipframe = KNXIPFrame.init_from_body( ConnectRequest( request_type=ConnectRequestType.TUNNEL_CONNECTION, control_endpoint=local_hpai, data_endpoint=local_hpai, )) with patch( "xknx.io.transport.UDPTransport.send") as mock_udp_send, patch( "xknx.io.transport.UDPTransport.getsockname" ) as mock_udp_getsockname: mock_udp_getsockname.return_value = ("192.168.1.3", 4321) await connect.start() mock_udp_send.assert_called_with(exp_knxipframe) # Response KNX/IP-Frame with wrong type wrong_knxipframe = KNXIPFrame() wrong_knxipframe.init(KNXIPServiceType.CONNECTIONSTATE_REQUEST) with patch("logging.Logger.warning") as mock_warning: connect.response_rec_callback(wrong_knxipframe, HPAI(), None) mock_warning.assert_called_with("Could not understand knxipframe") # Response KNX/IP-Frame with error: err_knxipframe = KNXIPFrame() err_knxipframe.init(KNXIPServiceType.CONNECT_RESPONSE) err_knxipframe.body.status_code = ErrorCode.E_CONNECTION_ID with patch("logging.Logger.debug") as mock_warning: connect.response_rec_callback(err_knxipframe, HPAI(), None) mock_warning.assert_called_with( "Error: KNX bus responded to request of type '%s' with error in '%s': %s", type(connect).__name__, type(err_knxipframe.body).__name__, ErrorCode.E_CONNECTION_ID, ) # Correct Response KNX/IP-Frame: res_knxipframe = KNXIPFrame() res_knxipframe.init(KNXIPServiceType.CONNECT_RESPONSE) res_knxipframe.body.communication_channel = 23 res_knxipframe.body.identifier = 7 connect.response_rec_callback(res_knxipframe, HPAI(), None) assert connect.success assert connect.communication_channel == 23 assert connect.identifier == 7
def test_connect_request(self): """Test parsing and streaming connection request KNX/IP packet.""" raw = ( 0x06, 0x10, 0x02, 0x05, 0x00, 0x1A, 0x08, 0x01, 0xC0, 0xA8, 0x2A, 0x01, 0x84, 0x95, 0x08, 0x01, 0xC0, 0xA8, 0x2A, 0x01, 0xCC, 0xA9, 0x04, 0x04, 0x02, 0x00, ) xknx = XKNX() knxipframe = KNXIPFrame(xknx) knxipframe.from_knx(raw) self.assertTrue(isinstance(knxipframe.body, ConnectRequest)) self.assertEqual( knxipframe.body.request_type, ConnectRequestType.TUNNEL_CONNECTION ) self.assertEqual( knxipframe.body.control_endpoint, HPAI(ip_addr="192.168.42.1", port=33941) ) self.assertEqual( knxipframe.body.data_endpoint, HPAI(ip_addr="192.168.42.1", port=52393) ) connect_request = ConnectRequest( xknx, request_type=ConnectRequestType.TUNNEL_CONNECTION, control_endpoint=HPAI(ip_addr="192.168.42.1", port=33941), data_endpoint=HPAI(ip_addr="192.168.42.1", port=52393), ) knxipframe2 = KNXIPFrame.init_from_body(connect_request) self.assertEqual(knxipframe2.to_knx(), list(raw))
def test_connect_request(self): """Test string representation of KNX/IP ConnectRequest.""" xknx = XKNX(loop=self.loop) connect_request = ConnectRequest(xknx) connect_request.request_type = ConnectRequestType.TUNNEL_CONNECTION connect_request.control_endpoint = HPAI(ip_addr='192.168.42.1', port=33941) connect_request.data_endpoint = HPAI(ip_addr='192.168.42.2', port=33942) self.assertEqual( str(connect_request), '<ConnectRequest control_endpoint="<HPAI 192.168.42.1:33941 />" data_endpoint="<HPAI 192.168.42.2:33942 />" request_type="ConnectRequest' 'Type.TUNNEL_CONNECTION" />')
def test_connect_request(self): """Test string representation of KNX/IP ConnectRequest.""" xknx = XKNX() connect_request = ConnectRequest(xknx) connect_request.request_type = ConnectRequestType.TUNNEL_CONNECTION connect_request.control_endpoint = HPAI(ip_addr="192.168.42.1", port=33941) connect_request.data_endpoint = HPAI(ip_addr="192.168.42.2", port=33942) assert ( str(connect_request) == '<ConnectRequest control_endpoint="<HPAI 192.168.42.1:33941 />" data_endpoint="<HPAI 192.168.42.2:33942 />" ' 'request_type="ConnectRequestType.TUNNEL_CONNECTION" />' )
def create_knxipframe(self) -> KNXIPFrame: """Create KNX/IP Frame object to be sent to device.""" (local_addr, local_port) = self.udp_client.getsockname() # set control_endpoint and data_endpoint to the same udp_connection endpoint = HPAI(ip_addr=local_addr, port=local_port) connect_request = ConnectRequest( self.xknx, request_type=ConnectRequestType.TUNNEL_CONNECTION, control_endpoint=endpoint, data_endpoint=endpoint, ) return KNXIPFrame.init_from_body(connect_request)
def test_connect_request(self): """Test parsing and streaming connection request KNX/IP packet.""" raw = bytes.fromhex("06 10 02 05 00 1A 08 01 C0 A8 2A 01 84 95 08 01" "C0 A8 2A 01 CC A9 04 04 02 00") knxipframe = KNXIPFrame() knxipframe.from_knx(raw) assert isinstance(knxipframe.body, ConnectRequest) assert knxipframe.body.request_type == ConnectRequestType.TUNNEL_CONNECTION assert knxipframe.body.control_endpoint == HPAI(ip_addr="192.168.42.1", port=33941) assert knxipframe.body.data_endpoint == HPAI(ip_addr="192.168.42.1", port=52393) connect_request = ConnectRequest( request_type=ConnectRequestType.TUNNEL_CONNECTION, control_endpoint=HPAI(ip_addr="192.168.42.1", port=33941), data_endpoint=HPAI(ip_addr="192.168.42.1", port=52393), ) knxipframe2 = KNXIPFrame.init_from_body(connect_request) assert knxipframe2.to_knx() == raw
async def test_tunnel_connect_send_disconnect( self, time_travel, route_back, data_endpoint_addr, local_endpoint ): """Test initiating a tunnelling connection.""" local_addr = ("192.168.1.1", 12345) remote_addr = ("192.168.1.2", 3671) self.tunnel.route_back = route_back gateway_data_endpoint = ( HPAI(*data_endpoint_addr) if data_endpoint_addr else HPAI() ) self.tunnel.transport.connect = AsyncMock() self.tunnel.transport.getsockname = Mock(return_value=local_addr) self.tunnel.transport.send = Mock() self.tunnel.transport.stop = Mock() # Connect connect_request = ConnectRequest( control_endpoint=local_endpoint, data_endpoint=local_endpoint, ) connect_frame = KNXIPFrame.init_from_body(connect_request) connection_task = asyncio.create_task(self.tunnel.connect()) await time_travel(0) self.tunnel.transport.connect.assert_called_once() self.tunnel.transport.send.assert_called_once_with(connect_frame) connect_response_frame = KNXIPFrame.init_from_body( ConnectResponse( communication_channel=23, data_endpoint=gateway_data_endpoint, identifier=7, ) ) self.tunnel.transport.handle_knxipframe(connect_response_frame, remote_addr) await connection_task assert self.tunnel._data_endpoint_addr == data_endpoint_addr assert self.tunnel._src_address == IndividualAddress(7) # Send - use data endpoint self.tunnel.transport.send.reset_mock() test_telegram = Telegram(payload=GroupValueWrite(DPTArray((1,)))) test_telegram_frame = KNXIPFrame.init_from_body( TunnellingRequest( communication_channel_id=23, sequence_counter=0, cemi=CEMIFrame.init_from_telegram( test_telegram, code=CEMIMessageCode.L_DATA_REQ, src_addr=IndividualAddress(7), ), ) ) asyncio.create_task(self.tunnel.send_telegram(test_telegram)) await time_travel(0) self.tunnel.transport.send.assert_called_once_with( test_telegram_frame, addr=data_endpoint_addr ) # skip ack and confirmation # Disconnect self.tunnel.transport.send.reset_mock() disconnect_request = DisconnectRequest( communication_channel_id=23, control_endpoint=local_endpoint, ) disconnect_frame = KNXIPFrame.init_from_body(disconnect_request) disconnection_task = asyncio.create_task(self.tunnel.disconnect()) await time_travel(0) self.tunnel.transport.send.assert_called_once_with(disconnect_frame) disconnect_response_frame = KNXIPFrame.init_from_body( DisconnectResponse(communication_channel_id=23) ) self.tunnel.transport.handle_knxipframe(disconnect_response_frame, remote_addr) await disconnection_task assert self.tunnel._data_endpoint_addr is None self.tunnel.transport.stop.assert_called_once()