def test_from_knx_wrong_info(self): """Test parsing and streaming wrong ConnectionStateRequest.""" raw = ((0x06, 0x10, 0x02, 0x07, 0x00, 0x010)) xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) with self.assertRaises(CouldNotParseKNXIP): knxipframe.from_knx(raw)
def test_from_knx_wrong_length(self): """Test parsing and streaming wrong DisconnectResponse.""" raw = ((0x06, 0x10, 0x02, 0x0A, 0x00, 0x08, 0x15)) xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) with self.assertRaises(CouldNotParseKNXIP): knxipframe.from_knx(raw)
def test_from_knx_wrong_header2(self): """Test parsing and streaming wrong TunnellingRequest (wrong header length).""" raw = ((0x06, 0x10, 0x04, 0x20, 0x00, 0x15, 0x04)) xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) with self.assertRaises(CouldNotParseKNXIP): knxipframe.from_knx(raw)
def test_from_knx_wrong_header(self): """Test parsing and streaming wrong ConnectionStateResponse (wrong header length).""" raw = ((0x06, 0x10, 0x02, 0x08, 0x00, 0x08, 0x15)) xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) with self.assertRaises(CouldNotParseKNXIP): knxipframe.from_knx(raw)
def test_from_knx_wrong_ack_information2(self): """Test parsing and streaming wrong TunnellingAck (wrong length).""" raw = ((0x06, 0x10, 0x04, 0x21, 0x00, 0x0a, 0x04, 0x2a, 0x17)) xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) with self.assertRaises(CouldNotParseKNXIP): knxipframe.from_knx(raw)
def test_parsing_too_long_knxip(self): """Test parsing and streaming connection state request KNX/IP packet.""" raw = ((0x06, 0x10, 0x02, 0x07, 0x00, 0x10, 0x15, 0x00, 0x08, 0x01, 0xC0, 0xA8, 0xC8, 0x0C, 0xC3, 0xB4, 0x00)) xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) with self.assertRaises(CouldNotParseKNXIP): knxipframe.from_knx(raw)
def send_ack(self, communication_channel_id, sequence_counter): """Send tunnelling ACK after tunnelling request received.""" ack_knxipframe = KNXIPFrame(self.xknx) ack_knxipframe.init(KNXIPServiceType.TUNNELLING_ACK) ack_knxipframe.body.communication_channel_id = communication_channel_id ack_knxipframe.body.sequence_counter = sequence_counter ack_knxipframe.normalize() self.udp_client.send(ack_knxipframe)
def create_knxipframe(self): """Create KNX/IP Frame object to be sent to device.""" knxipframe = KNXIPFrame(self.xknx) knxipframe.init(KNXIPServiceType.TUNNELLING_REQUEST) knxipframe.body.communication_channel_id = self.communication_channel_id knxipframe.body.cemi.telegram = self.telegram knxipframe.body.cemi.src_addr = self.src_address knxipframe.body.sequence_counter = self.sequence_counter return knxipframe
async def send_telegram(self, telegram): """Send Telegram to routing connected device.""" knxipframe = KNXIPFrame(self.xknx) knxipframe.init(KNXIPServiceType.ROUTING_INDICATION) knxipframe.body.src_addr = self.xknx.own_address knxipframe.body.telegram = telegram knxipframe.body.sender = self.xknx.own_address knxipframe.normalize() await self.send_knxipframe(knxipframe)
def create_knxipframe(self): """Create KNX/IP Frame object to be sent to device.""" (local_addr, local_port) = self.udpclient.getsockname() knxipframe = KNXIPFrame(self.xknx) knxipframe.init(KNXIPServiceType.DISCONNECT_REQUEST) knxipframe.body.communication_channel_id = \ self.communication_channel_id knxipframe.body.control_endpoint = HPAI( ip_addr=local_addr, port=local_port) return knxipframe
def test_knxip_frame(self): """Test string representation of KNX/IP Frame.""" xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) knxipframe.init(KNXIPServiceType.SEARCH_REQUEST) self.assertEqual( str(knxipframe), '<KNXIPFrame <KNXIPHeader HeaderLength="6" ProtocolVersion="16" KNXIPServiceType="KNXIPServiceType.SEARCH_REQUEST" Reserve="0" TotalLeng' 'th="0" />\n' ' body="<SearchRequest discovery_endpoint="<HPAI 224.0.23.12:3671 />" />" />')
def test_connect_request(self): """Test parsing and streaming connection tunneling request KNX/IP packet.""" raw = ((0x06, 0x10, 0x04, 0x20, 0x00, 0x15, 0x04, 0x01, 0x17, 0x00, 0x11, 0x00, 0xbc, 0xe0, 0x00, 0x00, 0x48, 0x08, 0x01, 0x00, 0x81)) xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) knxipframe.from_knx(raw) self.assertTrue(isinstance(knxipframe.body, TunnellingRequest)) self.assertEqual(knxipframe.body.communication_channel_id, 1) self.assertEqual(knxipframe.body.sequence_counter, 23) self.assertTrue(isinstance(knxipframe.body.cemi, CEMIFrame)) self.assertEqual(knxipframe.body.cemi.telegram, Telegram(GroupAddress('9/0/8'), payload=DPTBinary(1))) knxipframe2 = KNXIPFrame(xknx) knxipframe2.init(KNXIPServiceType.TUNNELLING_REQUEST) knxipframe2.body.cemi.telegram = Telegram( GroupAddress('9/0/8'), payload=DPTBinary(1)) knxipframe2.body.sequence_counter = 23 knxipframe2.normalize() self.assertEqual(knxipframe2.to_knx(), list(raw))
async def _search_interface(self, interface, ip_addr): """Send a search request on a specific interface.""" self.xknx.logger.debug("Searching on %s / %s", interface, ip_addr) udp_client = UDPClient(self.xknx, (ip_addr, 0, interface), (DEFAULT_MCAST_GRP, DEFAULT_MCAST_PORT), multicast=True) udp_client.register_callback( self._response_rec_callback, [KNXIPServiceType.SEARCH_RESPONSE]) await udp_client.connect() self._udp_clients.append(udp_client) (local_addr, local_port) = udp_client.getsockname() knx_ip_frame = KNXIPFrame(self.xknx) knx_ip_frame.init(KNXIPServiceType.SEARCH_REQUEST) knx_ip_frame.body.discovery_endpoint = \ HPAI(ip_addr=local_addr, port=local_port) knx_ip_frame.normalize() udp_client.send(knx_ip_frame)
def test_search_response(self): """Test parsing and streaming SearchResponse KNX/IP packet.""" raw = ((0x06, 0x10, 0x02, 0x02, 0x00, 0x50, 0x08, 0x01, 0xc0, 0xa8, 0x2a, 0x0a, 0x0e, 0x57, 0x36, 0x01, 0x02, 0x00, 0x11, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xe0, 0x00, 0x17, 0x0c, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x47, 0x69, 0x72, 0x61, 0x20, 0x4b, 0x4e, 0x58, 0x2f, 0x49, 0x50, 0x2d, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x02, 0x02, 0x01, 0x03, 0x02, 0x04, 0x01, 0x05, 0x01, 0x07, 0x01)) xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) self.assertEqual(knxipframe.from_knx(raw), 80) self.assertEqual(knxipframe.to_knx(), list(raw)) self.assertTrue(isinstance(knxipframe.body, SearchResponse)) self.assertEqual( knxipframe.body.control_endpoint, HPAI("192.168.42.10", 3671)) self.assertEqual(len(knxipframe.body.dibs), 2) # Specific testing of parsing and serializing of # DIBDeviceInformation and DIBSuppSVCFamilies is # done within knxip_dib_test.py self.assertTrue(isinstance( knxipframe.body.dibs[0], DIBDeviceInformation)) self.assertTrue(isinstance( knxipframe.body.dibs[1], DIBSuppSVCFamilies)) self.assertEqual(knxipframe.body.device_name, "Gira KNX/IP-Router") self.assertTrue(knxipframe.body.dibs[1].supports(DIBServiceFamily.ROUTING)) self.assertTrue(knxipframe.body.dibs[1].supports(DIBServiceFamily.TUNNELING)) self.assertFalse(knxipframe.body.dibs[1].supports(DIBServiceFamily.OBJECT_SERVER)) knxipframe2 = KNXIPFrame(xknx) knxipframe2.init(KNXIPServiceType.SEARCH_RESPONSE) knxipframe2.body.control_endpoint = \ HPAI(ip_addr="192.168.42.10", port=3671) knxipframe2.body.dibs.append(knxipframe.body.dibs[0]) knxipframe2.body.dibs.append(knxipframe.body.dibs[1]) knxipframe2.normalize() self.assertEqual(knxipframe2.to_knx(), list(raw))
def test_search_request(self): """Test parsing and streaming SearchRequest KNX/IP packet.""" raw = ((0x06, 0x10, 0x02, 0x01, 0x00, 0x0e, 0x08, 0x01, 0xe0, 0x00, 0x17, 0x0c, 0x0e, 0x57)) xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) knxipframe.from_knx(raw) self.assertTrue(isinstance(knxipframe.body, SearchRequest)) self.assertEqual( knxipframe.body.discovery_endpoint, HPAI(ip_addr="224.0.23.12", port=3671)) knxipframe2 = KNXIPFrame(xknx) knxipframe2.init(KNXIPServiceType.SEARCH_REQUEST) knxipframe2.body.discovery_endpoint = \ HPAI(ip_addr="224.0.23.12", port=3671) knxipframe2.normalize() self.assertEqual(knxipframe2.to_knx(), list(raw))
def test_disconnect_response(self): """Test parsing and streaming connection state response KNX/IP packet.""" raw = ((0x06, 0x10, 0x02, 0x08, 0x00, 0x08, 0x15, 0x21)) xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) knxipframe.from_knx(raw) self.assertTrue(isinstance(knxipframe.body, ConnectionStateResponse)) self.assertEqual( knxipframe.body.communication_channel_id, 21) self.assertEqual( knxipframe.body.status_code, ErrorCode.E_CONNECTION_ID) knxipframe2 = KNXIPFrame(xknx) knxipframe2.init(KNXIPServiceType.CONNECTIONSTATE_RESPONSE) knxipframe2.body.communication_channel_id = 21 knxipframe2.body.status_code = ErrorCode.E_CONNECTION_ID knxipframe2.normalize() self.assertEqual(knxipframe2.to_knx(), list(raw))
def test_connect_request(self): """Test parsing and streaming tunneling ACK KNX/IP packet.""" raw = ((0x06, 0x10, 0x04, 0x21, 0x00, 0x0a, 0x04, 0x2a, 0x17, 0x00)) xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) knxipframe.from_knx(raw) self.assertTrue(isinstance(knxipframe.body, TunnellingAck)) self.assertEqual(knxipframe.body.communication_channel_id, 42) self.assertEqual(knxipframe.body.sequence_counter, 23) self.assertEqual( knxipframe.body.status_code, ErrorCode.E_NO_ERROR) knxipframe2 = KNXIPFrame(xknx) knxipframe2.init(KNXIPServiceType.TUNNELLING_ACK) knxipframe2.body.communication_channel_id = 42 knxipframe2.body.sequence_counter = 23 knxipframe2.normalize() self.assertEqual(knxipframe2.to_knx(), list(raw))
def test_disconnect_request(self): """Test parsing and streaming DisconnectRequest KNX/IP packet.""" raw = ((0x06, 0x10, 0x02, 0x09, 0x00, 0x10, 0x15, 0x00, 0x08, 0x01, 0xC0, 0xA8, 0xC8, 0x0C, 0xC3, 0xB4)) xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) knxipframe.from_knx(raw) self.assertTrue(isinstance(knxipframe.body, DisconnectRequest)) self.assertEqual( knxipframe.body.communication_channel_id, 21) self.assertEqual( knxipframe.body.control_endpoint, HPAI(ip_addr='192.168.200.12', port=50100)) knxipframe2 = KNXIPFrame(xknx) knxipframe2.init(KNXIPServiceType.DISCONNECT_REQUEST) knxipframe2.body.communication_channel_id = 21 knxipframe2.body.control_endpoint = HPAI( ip_addr='192.168.200.12', port=50100) knxipframe2.normalize() self.assertEqual(knxipframe2.to_knx(), list(raw))
def fake_router_search_response(xknx: XKNX) -> SearchResponse: """Return the SearchResponse of a KNX/IP Router.""" _frame_header = KNXIPHeader(xknx) _frame_header.service_type_ident = KNXIPServiceType.SEARCH_RESPONSE _frame_body = SearchResponse(xknx) _frame_body.control_endpoint = HPAI(ip_addr="192.168.42.10", port=3671) _device_information = DIBDeviceInformation() _device_information.name = "Gira KNX/IP-Router" _device_information.serial_number = "11:22:33:44:55:66" _device_information.individual_address = PhysicalAddress("1.1.0") _device_information.mac_address = "01:02:03:04:05:06" _svc_families = DIBSuppSVCFamilies() _svc_families.families.append( DIBSuppSVCFamilies.Family(name=DIBServiceFamily.CORE, version=1)) _svc_families.families.append( DIBSuppSVCFamilies.Family(name=DIBServiceFamily.DEVICE_MANAGEMENT, version=2)) _svc_families.families.append( DIBSuppSVCFamilies.Family(name=DIBServiceFamily.TUNNELING, version=1)) _svc_families.families.append( DIBSuppSVCFamilies.Family(name=DIBServiceFamily.ROUTING, version=1)) _svc_families.families.append( DIBSuppSVCFamilies.Family(name=DIBServiceFamily.REMOTE_CONFIGURATION_DIAGNOSIS, version=1)) _frame_body.dibs.append(_device_information) _frame_body.dibs.append(_svc_families) _frame_header.set_length(_frame_body) search_response = KNXIPFrame(xknx) search_response.init(KNXIPServiceType.SEARCH_RESPONSE) search_response.header = _frame_header search_response.body = _frame_body search_response.normalize() return search_response
def test_EndTOEnd_group_read(self): """Test parsing and streaming CEMIFrame KNX/IP packet, group read.""" # State request raw = ((0x06, 0x10, 0x05, 0x30, 0x00, 0x11, 0x29, 0x00, 0xbc, 0xd0, 0xff, 0xf9, 0x01, 0xb8, 0x01, 0x00, 0x00)) xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) knxipframe.from_knx(raw) telegram = knxipframe.body.cemi.telegram self.assertEqual( telegram, Telegram(GroupAddress("440"), TelegramType.GROUP_READ)) knxipframe2 = KNXIPFrame(xknx) knxipframe2.init(KNXIPServiceType.ROUTING_INDICATION) knxipframe2.body.cemi.src_addr = PhysicalAddress("15.15.249") knxipframe2.body.cemi.telegram = telegram knxipframe2.body.cemi.set_hops(5) knxipframe2.normalize() self.assertEqual(knxipframe2.header.to_knx(), list(raw[0:6])) self.assertEqual(knxipframe2.body.to_knx(), list(raw[6:])) self.assertEqual(knxipframe2.to_knx(), list(raw))
def test_connect_request(self): """Test parsing and streaming SearchResponse KNX/IP packet.""" raw = ((0x06, 0x10, 0x02, 0x02, 0x00, 0x50, 0x08, 0x01, 0xc0, 0xa8, 0x2a, 0x0a, 0x0e, 0x57, 0x36, 0x01, 0x02, 0x00, 0x11, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xe0, 0x00, 0x17, 0x0c, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x47, 0x69, 0x72, 0x61, 0x20, 0x4b, 0x4e, 0x58, 0x2f, 0x49, 0x50, 0x2d, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x02, 0x02, 0x01, 0x03, 0x02, 0x04, 0x01, 0x05, 0x01, 0x07, 0x01)) xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) self.assertEqual(knxipframe.from_knx(raw), 80) self.assertEqual(knxipframe.to_knx(), list(raw)) self.assertTrue(isinstance(knxipframe.body, SearchResponse)) self.assertEqual(knxipframe.body.control_endpoint, HPAI("192.168.42.10", 3671)) self.assertEqual(len(knxipframe.body.dibs), 2) # Specific testing of parsing and serializing of # DIBDeviceInformation and DIBSuppSVCFamilies is # done within knxip_dib_test.py self.assertTrue( isinstance(knxipframe.body.dibs[0], DIBDeviceInformation)) self.assertTrue(isinstance(knxipframe.body.dibs[1], DIBSuppSVCFamilies)) self.assertEqual(knxipframe.body.device_name, "Gira KNX/IP-Router") self.assertTrue(knxipframe.body.dibs[1].supports( DIBServiceFamily.ROUTING)) self.assertTrue(knxipframe.body.dibs[1].supports( DIBServiceFamily.TUNNELING)) self.assertFalse(knxipframe.body.dibs[1].supports( DIBServiceFamily.OBJECT_SERVER)) knxipframe2 = KNXIPFrame(xknx) knxipframe2.init(KNXIPServiceType.SEARCH_RESPONSE) knxipframe2.body.control_endpoint = \ HPAI(ip_addr="192.168.42.10", port=3671) knxipframe2.body.dibs.append(knxipframe.body.dibs[0]) knxipframe2.body.dibs.append(knxipframe.body.dibs[1]) knxipframe2.normalize() self.assertEqual(knxipframe2.to_knx(), list(raw))
def test_EndTOEnd_group_response(self): """Test parsing and streaming CEMIFrame KNX/IP packet, group response.""" # Incoming state raw = ((0x06, 0x10, 0x05, 0x30, 0x00, 0x11, 0x29, 0x00, 0xbc, 0xd0, 0x13, 0x01, 0x01, 0x88, 0x01, 0x00, 0x41)) xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) knxipframe.from_knx(raw) telegram = knxipframe.body.cemi.telegram self.assertEqual( telegram, Telegram(GroupAddress("392"), TelegramType.GROUP_RESPONSE, payload=DPTBinary(1))) knxipframe2 = KNXIPFrame(xknx) knxipframe2.init(KNXIPServiceType.ROUTING_INDICATION) knxipframe2.body.cemi.src_addr = PhysicalAddress("1.3.1") knxipframe2.body.cemi.telegram = telegram knxipframe2.body.cemi.set_hops(5) knxipframe2.normalize() self.assertEqual(knxipframe2.header.to_knx(), list(raw[0:6])) self.assertEqual(knxipframe2.body.to_knx(), list(raw[6:])) self.assertEqual(knxipframe2.to_knx(), list(raw))
async def test_tunnelling(self): """Test tunnelling from KNX bus.""" communication_channel_id = 23 data_endpoint = ("192.168.1.2", 4567) udp_transport = UDPTransport(("192.168.1.1", 0), ("192.168.1.2", 1234)) telegram = Telegram( destination_address=GroupAddress("1/2/3"), payload=GroupValueWrite(DPTArray((0x1, 0x2, 0x3))), ) sequence_counter = 42 src_address = IndividualAddress("2.2.2") tunnelling = Tunnelling( udp_transport, data_endpoint, telegram, src_address, sequence_counter, communication_channel_id, ) tunnelling.timeout_in_seconds = 0 assert tunnelling.awaited_response_class == TunnellingAck assert tunnelling.communication_channel_id == communication_channel_id # Expected KNX/IP-Frame: tunnelling_request = TunnellingRequest( communication_channel_id=communication_channel_id, sequence_counter=sequence_counter, ) tunnelling_request.cemi.telegram = telegram tunnelling_request.cemi.src_addr = src_address exp_knxipframe = KNXIPFrame.init_from_body(tunnelling_request) 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 tunnelling.start() mock_udp_send.assert_called_with(exp_knxipframe, addr=data_endpoint) # Response KNX/IP-Frame with wrong type wrong_knxipframe = KNXIPFrame() wrong_knxipframe.init(KNXIPServiceType.CONNECTIONSTATE_REQUEST) with patch("logging.Logger.warning") as mock_warning: tunnelling.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.TUNNELLING_ACK) err_knxipframe.body.status_code = ErrorCode.E_CONNECTION_ID with patch("logging.Logger.debug") as mock_warning: tunnelling.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(tunnelling).__name__, type(err_knxipframe.body).__name__, ErrorCode.E_CONNECTION_ID, ) # Correct Response KNX/IP-Frame: res_knxipframe = KNXIPFrame() res_knxipframe.init(KNXIPServiceType.TUNNELLING_ACK) tunnelling.response_rec_callback(res_knxipframe, HPAI(), None) assert tunnelling.success
def test_search_request(self): """Test parsing and streaming SearchRequest KNX/IP packet.""" raw = ( 0x06, 0x10, 0x02, 0x01, 0x00, 0x0E, 0x08, 0x01, 0xE0, 0x00, 0x17, 0x0C, 0x0E, 0x57, ) xknx = XKNX() knxipframe = KNXIPFrame(xknx) knxipframe.from_knx(raw) self.assertTrue(isinstance(knxipframe.body, SearchRequest)) self.assertEqual(knxipframe.body.discovery_endpoint, HPAI(ip_addr="224.0.23.12", port=3671)) knxipframe2 = KNXIPFrame(xknx) knxipframe2.init(KNXIPServiceType.SEARCH_REQUEST) knxipframe2.body.discovery_endpoint = HPAI(ip_addr="224.0.23.12", port=3671) knxipframe2.normalize() self.assertEqual(knxipframe2.to_knx(), list(raw))
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(loop=self.loop) 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)) knxipframe2 = KNXIPFrame(xknx) knxipframe2.init(KNXIPServiceType.CONNECT_REQUEST) knxipframe2.body.request_type = ConnectRequestType.TUNNEL_CONNECTION knxipframe2.body.control_endpoint = HPAI(ip_addr='192.168.42.1', port=33941) knxipframe2.body.data_endpoint = HPAI(ip_addr='192.168.42.1', port=52393) knxipframe2.normalize() self.assertEqual(knxipframe2.to_knx(), list(raw))
def test_EndTOEnd_group_write_1byte(self): """Test parsing and streaming CEMIFrame KNX/IP packet, dimm light in my kitchen.""" # Dimm Kitchen L1 to 0x65 raw = ((0x06, 0x10, 0x05, 0x30, 0x00, 0x12, 0x29, 0x00, 0xbc, 0xd0, 0xff, 0xf9, 0x01, 0x4b, 0x02, 0x00, 0x80, 0x65)) xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) knxipframe.from_knx(raw) telegram = knxipframe.body.cemi.telegram self.assertEqual(telegram, Telegram(GroupAddress("331"), payload=DPTArray(0x65))) knxipframe2 = KNXIPFrame(xknx) knxipframe2.init(KNXIPServiceType.ROUTING_INDICATION) knxipframe2.body.cemi.src_addr = PhysicalAddress("15.15.249") knxipframe2.body.cemi.telegram = telegram knxipframe2.body.cemi.set_hops(5) knxipframe2.normalize() self.assertEqual(knxipframe2.header.to_knx(), list(raw[0:6])) self.assertEqual(knxipframe2.body.to_knx(), list(raw[6:])) self.assertEqual(knxipframe2.to_knx(), list(raw))
def test_parsing_too_short_knxip(self): """Test parsing and streaming connection state request KNX/IP packet.""" raw = bytes.fromhex("06 10 02 07 00 10 15 00 08 01 C0 A8 C8 0C C3") knxipframe = KNXIPFrame() with pytest.raises(IncompleteKNXIPFrame): knxipframe.from_knx(raw)
async def test_connectionstate_route_back_true(self): """Test connectionstateing from KNX bus.""" communication_channel_id = 23 udp_transport = UDPTransport(("192.168.1.1", 0), ("192.168.1.2", 1234)) local_hpai = HPAI() connectionstate = ConnectionState(udp_transport, communication_channel_id, local_hpai=local_hpai) connectionstate.timeout_in_seconds = 0 assert connectionstate.awaited_response_class == ConnectionStateResponse assert connectionstate.communication_channel_id == communication_channel_id # Expected KNX/IP-Frame: exp_knxipframe = KNXIPFrame.init_from_body( ConnectionStateRequest( communication_channel_id=communication_channel_id, )) 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 connectionstate.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: connectionstate.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.CONNECTIONSTATE_RESPONSE) err_knxipframe.body.status_code = ErrorCode.E_CONNECTION_ID with patch("logging.Logger.debug") as mock_warning: connectionstate.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(connectionstate).__name__, type(err_knxipframe.body).__name__, ErrorCode.E_CONNECTION_ID, ) # Correct Response KNX/IP-Frame: res_knxipframe = KNXIPFrame() res_knxipframe.init(KNXIPServiceType.CONNECTIONSTATE_RESPONSE) connectionstate.response_rec_callback(res_knxipframe, HPAI(), None) assert connectionstate.success
def test_connect_response(self): """Test parsing and streaming connection response KNX/IP packet.""" raw = ((0x06, 0x10, 0x02, 0x06, 0x00, 0x14, 0x01, 0x00, 0x08, 0x01, 0xc0, 0xa8, 0x2a, 0x0a, 0x0e, 0x57, 0x04, 0x04, 0x11, 0xff)) xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) knxipframe.from_knx(raw) self.assertTrue(isinstance(knxipframe.body, ConnectResponse)) self.assertEqual(knxipframe.body.communication_channel, 1) self.assertEqual(knxipframe.body.status_code, ErrorCode.E_NO_ERROR) self.assertEqual(knxipframe.body.control_endpoint, HPAI(ip_addr='192.168.42.10', port=3671)) self.assertEqual(knxipframe.body.request_type, ConnectRequestType.TUNNEL_CONNECTION) self.assertEqual(knxipframe.body.identifier, 4607) knxipframe2 = KNXIPFrame(xknx) knxipframe2.init(KNXIPServiceType.CONNECT_RESPONSE) knxipframe2.status_code = ErrorCode.E_NO_ERROR knxipframe2.body.communication_channel = 1 knxipframe2.body.request_type = ConnectRequestType.TUNNEL_CONNECTION knxipframe2.body.control_endpoint = HPAI(ip_addr='192.168.42.10', port=3671) knxipframe2.body.identifier = 4607 knxipframe2.normalize() self.assertEqual(knxipframe2.to_knx(), list(raw))
def test_search_response(self): """Test parsing and streaming SearchResponse KNX/IP packet.""" raw = ( 0x06, 0x10, 0x02, 0x02, 0x00, 0x50, 0x08, 0x01, 0xC0, 0xA8, 0x2A, 0x0A, 0x0E, 0x57, 0x36, 0x01, 0x02, 0x00, 0x11, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xE0, 0x00, 0x17, 0x0C, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x47, 0x69, 0x72, 0x61, 0x20, 0x4B, 0x4E, 0x58, 0x2F, 0x49, 0x50, 0x2D, 0x52, 0x6F, 0x75, 0x74, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x02, 0x02, 0x01, 0x03, 0x02, 0x04, 0x01, 0x05, 0x01, 0x07, 0x01, ) xknx = XKNX() knxipframe = KNXIPFrame(xknx) assert knxipframe.from_knx(raw) == 80 assert knxipframe.to_knx() == list(raw) assert isinstance(knxipframe.body, SearchResponse) assert knxipframe.body.control_endpoint == HPAI("192.168.42.10", 3671) assert len(knxipframe.body.dibs) == 2 # Specific testing of parsing and serializing of # DIBDeviceInformation and DIBSuppSVCFamilies is # done within knxip_dib_test.py assert isinstance(knxipframe.body.dibs[0], DIBDeviceInformation) assert isinstance(knxipframe.body.dibs[1], DIBSuppSVCFamilies) assert knxipframe.body.device_name == "Gira KNX/IP-Router" assert knxipframe.body.dibs[1].supports(DIBServiceFamily.ROUTING) assert knxipframe.body.dibs[1].supports(DIBServiceFamily.TUNNELING) assert not knxipframe.body.dibs[1].supports(DIBServiceFamily.OBJECT_SERVER) search_response = SearchResponse( xknx, control_endpoint=HPAI(ip_addr="192.168.42.10", port=3671) ) search_response.dibs.append(knxipframe.body.dibs[0]) search_response.dibs.append(knxipframe.body.dibs[1]) knxipframe2 = KNXIPFrame.init_from_body(search_response) assert knxipframe2.to_knx() == list(raw)
def test_connect_request(self): raw = ((0x06, 0x10, 0x04, 0x21, 0x00, 0x0a, 0x04, 0x2a, 0x17, 0x00)) knxipframe = KNXIPFrame() knxipframe.from_knx(raw) self.assertTrue(isinstance(knxipframe.body, TunnellingAck)) self.assertEqual(knxipframe.body.communication_channel_id, 42) self.assertEqual(knxipframe.body.sequence_counter, 23) self.assertEqual(knxipframe.body.status_code, ErrorCode.E_NO_ERROR) knxipframe2 = KNXIPFrame() knxipframe2.init(KNXIPServiceType.TUNNELLING_ACK) knxipframe2.body.communication_channel_id = 42 knxipframe2.body.sequence_counter = 23 knxipframe2.normalize() self.assertEqual(knxipframe2.to_knx(), list(raw))
def test_from_knx_wrong_length(self): """Test parsing and streaming wrong DisconnectRequest.""" raw = bytes((0x06, 0x10, 0x02, 0x09, 0x00, 0x10)) knxipframe = KNXIPFrame() with pytest.raises(CouldNotParseKNXIP): knxipframe.from_knx(raw)
def test_disconnect_response(self): raw = ((0x06, 0x10, 0x02, 0x0A, 0x00, 0x08, 0x15, 0x25)) knxipframe = KNXIPFrame() knxipframe.from_knx(raw) self.assertTrue(isinstance(knxipframe.body, DisconnectResponse)) self.assertEqual(knxipframe.body.communication_channel_id, 21) self.assertEqual(knxipframe.body.status_code, ErrorCode.E_NO_MORE_UNIQUE_CONNECTIONS) knxipframe2 = KNXIPFrame() knxipframe2.init(KNXIPServiceType.DISCONNECT_RESPONSE) knxipframe2.body.communication_channel_id = 21 knxipframe2.body.status_code = ErrorCode.E_NO_MORE_UNIQUE_CONNECTIONS knxipframe2.normalize() self.assertEqual(knxipframe2.to_knx(), list(raw))
def test_connect_request(self): raw = ((0x06, 0x10, 0x02, 0x01, 0x00, 0x0e, 0x08, 0x01, 0xe0, 0x00, 0x17, 0x0c, 0x0e, 0x57)) knxipframe = KNXIPFrame() knxipframe.from_knx(raw) self.assertTrue(isinstance(knxipframe.body, SearchRequest)) self.assertEqual( knxipframe.body.discovery_endpoint, HPAI(ip_addr="224.0.23.12", port=3671)) knxipframe2 = KNXIPFrame() knxipframe2.init(KNXIPServiceType.SEARCH_REQUEST) knxipframe2.body.discovery_endpoint = \ HPAI(ip_addr="224.0.23.12", port=3671) knxipframe2.normalize() self.assertEqual(knxipframe2.to_knx(), list(raw))
def test_disconnect_request(self): """Test parsing and streaming DisconnectRequest KNX/IP packet.""" raw = ((0x06, 0x10, 0x02, 0x09, 0x00, 0x10, 0x15, 0x00, 0x08, 0x01, 0xC0, 0xA8, 0xC8, 0x0C, 0xC3, 0xB4)) xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) knxipframe.from_knx(raw) self.assertTrue(isinstance(knxipframe.body, DisconnectRequest)) self.assertEqual(knxipframe.body.communication_channel_id, 21) self.assertEqual(knxipframe.body.control_endpoint, HPAI(ip_addr='192.168.200.12', port=50100)) knxipframe2 = KNXIPFrame(xknx) knxipframe2.init(KNXIPServiceType.DISCONNECT_REQUEST) knxipframe2.body.communication_channel_id = 21 knxipframe2.body.control_endpoint = HPAI(ip_addr='192.168.200.12', port=50100) knxipframe2.normalize() self.assertEqual(knxipframe2.to_knx(), list(raw))
def test_wrong_init(self): """Testing init method with wrong service_type_ident.""" xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) with self.assertRaises(TypeError): knxipframe.init(23)
def test_to_knx_no_body(self): """Test to_knx method without body raises exception.""" knxipframe = KNXIPFrame() with pytest.raises(CouldNotParseKNXIP): knxipframe.to_knx()
def test_connect_response_connection_error(self): """Test parsing and streaming connection response KNX/IP packet with error.""" raw = (0x06, 0x10, 0x02, 0x06, 0x00, 0x08, 0x00, 0x24) xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) knxipframe.from_knx(raw) self.assertTrue(isinstance(knxipframe.body, ConnectResponse)) self.assertEqual(knxipframe.body.status_code, ErrorCode.E_NO_MORE_CONNECTIONS) self.assertEqual(knxipframe.body.communication_channel, 0) knxipframe2 = KNXIPFrame(xknx) knxipframe2.init(KNXIPServiceType.CONNECT_RESPONSE) knxipframe2.body.status_code = ErrorCode.E_NO_MORE_CONNECTIONS knxipframe2.normalize() self.assertEqual(knxipframe2.to_knx(), list(raw))
def test_connect(self): """Test connecting from KNX bus.""" xknx = XKNX(loop=self.loop) udp_client = UDPClient(xknx, ("192.168.1.1", 0), ("192.168.1.2", 1234)) connect = Connect(xknx, udp_client) connect.timeout_in_seconds = 0 self.assertEqual(connect.awaited_response_class, ConnectResponse) # Expected KNX/IP-Frame: exp_knxipframe = KNXIPFrame(xknx) exp_knxipframe.init(KNXIPServiceType.CONNECT_REQUEST) exp_knxipframe.body.control_endpoint = HPAI(ip_addr='192.168.1.3', port=4321) exp_knxipframe.body.data_endpoint = HPAI(ip_addr='192.168.1.3', port=4321) exp_knxipframe.body.request_type = ConnectRequestType.TUNNEL_CONNECTION exp_knxipframe.normalize() 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(asyncio.Task(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('Cant 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.warning') 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)
def test_disconnect_response(self): """Test parsing and streaming connection state response KNX/IP packet.""" raw = (0x06, 0x10, 0x02, 0x08, 0x00, 0x08, 0x15, 0x21) xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) knxipframe.from_knx(raw) self.assertTrue(isinstance(knxipframe.body, ConnectionStateResponse)) self.assertEqual(knxipframe.body.communication_channel_id, 21) self.assertEqual(knxipframe.body.status_code, ErrorCode.E_CONNECTION_ID) knxipframe2 = KNXIPFrame(xknx) knxipframe2.init(KNXIPServiceType.CONNECTIONSTATE_RESPONSE) knxipframe2.body.communication_channel_id = 21 knxipframe2.body.status_code = ErrorCode.E_CONNECTION_ID knxipframe2.normalize() self.assertEqual(knxipframe2.to_knx(), list(raw))
def test_tunnelling(self): """Test tunnelling from KNX bus.""" # pylint: disable=too-many-locals xknx = XKNX(loop=self.loop) communication_channel_id = 23 udp_client = UDPClient(xknx, ("192.168.1.1", 0), ("192.168.1.2", 1234)) telegram = Telegram(GroupAddress('1/2/3'), payload=DPTArray((0x1, 0x2, 0x3))) sequence_counter = 42 src_address = PhysicalAddress('2.2.2') tunnelling = Tunnelling(xknx, udp_client, telegram, src_address, sequence_counter, communication_channel_id) tunnelling.timeout_in_seconds = 0 self.assertEqual(tunnelling.awaited_response_class, TunnellingAck) self.assertEqual(tunnelling.communication_channel_id, communication_channel_id) # Expected KNX/IP-Frame: exp_knxipframe = KNXIPFrame(xknx) exp_knxipframe.init(KNXIPServiceType.TUNNELLING_REQUEST) exp_knxipframe.body.cemi.telegram = telegram exp_knxipframe.body.cemi.src_addr = src_address exp_knxipframe.body.communication_channel_id = communication_channel_id exp_knxipframe.body.sequence_counter = sequence_counter exp_knxipframe.normalize() print(exp_knxipframe) 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(asyncio.Task(tunnelling.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: tunnelling.response_rec_callback(wrong_knxipframe, None) mock_warning.assert_called_with('Cant understand knxipframe') # Response KNX/IP-Frame with error: err_knxipframe = KNXIPFrame(xknx) err_knxipframe.init(KNXIPServiceType.TUNNELLING_ACK) err_knxipframe.body.status_code = ErrorCode.E_CONNECTION_ID with patch('logging.Logger.warning') as mock_warning: tunnelling.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(tunnelling).__name__, type(err_knxipframe.body).__name__, ErrorCode.E_CONNECTION_ID) # Correct Response KNX/IP-Frame: res_knxipframe = KNXIPFrame(xknx) res_knxipframe.init(KNXIPServiceType.TUNNELLING_ACK) with patch('logging.Logger.debug') as mock_debug: tunnelling.response_rec_callback(res_knxipframe, None) mock_debug.assert_called_with('Success: received correct answer from KNX bus: %s', ErrorCode.E_NO_ERROR) self.assertTrue(tunnelling.success)
def test_connectionstate_route_back_true(self): """Test connectionstateing from KNX bus.""" xknx = XKNX() communication_channel_id = 23 udp_client = UDPClient(xknx, ("192.168.1.1", 0), ("192.168.1.2", 1234)) connectionstate = ConnectionState(xknx, udp_client, communication_channel_id, route_back=True) connectionstate.timeout_in_seconds = 0 self.assertEqual(connectionstate.awaited_response_class, ConnectionStateResponse) self.assertEqual(connectionstate.communication_channel_id, communication_channel_id) # Expected KNX/IP-Frame: exp_knxipframe = KNXIPFrame.init_from_body( ConnectionStateRequest( xknx, communication_channel_id=communication_channel_id, )) 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(connectionstate.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: connectionstate.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.CONNECTIONSTATE_RESPONSE) err_knxipframe.body.status_code = ErrorCode.E_CONNECTION_ID with patch("logging.Logger.debug") as mock_warning: connectionstate.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(connectionstate).__name__, type(err_knxipframe.body).__name__, ErrorCode.E_CONNECTION_ID, ) # Correct Response KNX/IP-Frame: res_knxipframe = KNXIPFrame(xknx) res_knxipframe.init(KNXIPServiceType.CONNECTIONSTATE_RESPONSE) connectionstate.response_rec_callback(res_knxipframe, None) self.assertTrue(connectionstate.success)
def test_connect_request(self): """Test parsing and streaming tunneling ACK KNX/IP packet.""" raw = (0x06, 0x10, 0x04, 0x21, 0x00, 0x0A, 0x04, 0x2A, 0x17, 0x00) xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) knxipframe.from_knx(raw) self.assertTrue(isinstance(knxipframe.body, TunnellingAck)) self.assertEqual(knxipframe.body.communication_channel_id, 42) self.assertEqual(knxipframe.body.sequence_counter, 23) self.assertEqual(knxipframe.body.status_code, ErrorCode.E_NO_ERROR) knxipframe2 = KNXIPFrame(xknx) knxipframe2.init(KNXIPServiceType.TUNNELLING_ACK) knxipframe2.body.communication_channel_id = 42 knxipframe2.body.sequence_counter = 23 knxipframe2.normalize() self.assertEqual(knxipframe2.to_knx(), list(raw))
def test_maximum_apci(self): """Test parsing and streaming CEMIFrame KNX/IP packet, testing maximum APCI.""" telegram = Telegram() telegram.group_address = GroupAddress(337) telegram.payload = DPTBinary(DPTBinary.APCI_MAX_VALUE) xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) knxipframe.init(KNXIPServiceType.ROUTING_INDICATION) knxipframe.body.cemi.src_addr = PhysicalAddress("1.3.1") knxipframe.body.cemi.telegram = telegram knxipframe.body.cemi.set_hops(5) knxipframe.normalize() raw = ((0x06, 0x10, 0x05, 0x30, 0x00, 0x11, 0x29, 0x00, 0xbc, 0xd0, 0x13, 0x01, 0x01, 0x51, 0x01, 0x00, 0xbf)) self.assertEqual(knxipframe.to_knx(), list(raw)) knxipframe2 = KNXIPFrame(xknx) knxipframe2.init(KNXIPServiceType.ROUTING_INDICATION) knxipframe2.from_knx(knxipframe.to_knx()) self.assertEqual(knxipframe2.body.cemi.telegram, telegram)
def test_connectionstate(self): """Test connectionstateing from KNX bus.""" xknx = XKNX(loop=self.loop) communication_channel_id = 23 udp_client = UDPClient(xknx, ("192.168.1.1", 0), ("192.168.1.2", 1234)) connectionstate = ConnectionState(xknx, udp_client, communication_channel_id) connectionstate.timeout_in_seconds = 0 self.assertEqual(connectionstate.awaited_response_class, ConnectionStateResponse) self.assertEqual(connectionstate.communication_channel_id, communication_channel_id) # Expected KNX/IP-Frame: exp_knxipframe = KNXIPFrame(xknx) exp_knxipframe.init(KNXIPServiceType.CONNECTIONSTATE_REQUEST) exp_knxipframe.body.communication_channel_id = communication_channel_id exp_knxipframe.body.control_endpoint = HPAI(ip_addr='192.168.1.3', port=4321) exp_knxipframe.normalize() 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(asyncio.Task(connectionstate.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: connectionstate.response_rec_callback(wrong_knxipframe, None) mock_warning.assert_called_with('Cant understand knxipframe') # Response KNX/IP-Frame with error: err_knxipframe = KNXIPFrame(xknx) err_knxipframe.init(KNXIPServiceType.CONNECTIONSTATE_RESPONSE) err_knxipframe.body.status_code = ErrorCode.E_CONNECTION_ID with patch('logging.Logger.warning') as mock_warning: connectionstate.response_rec_callback(err_knxipframe, None) mock_warning.assert_called_with( 'Error: reading rading group address from KNX bus failed: %s', ErrorCode.E_CONNECTION_ID) # Correct Response KNX/IP-Frame: res_knxipframe = KNXIPFrame(xknx) res_knxipframe.init(KNXIPServiceType.CONNECTIONSTATE_RESPONSE) with patch('logging.Logger.debug') as mock_debug: connectionstate.response_rec_callback(res_knxipframe, None) mock_debug.assert_called_with( 'Success: received correct answer from KNX bus: %s', ErrorCode.E_NO_ERROR) self.assertTrue(connectionstate.success)
def test_wrong_init(self): """Testing init method with wrong service_type_ident.""" xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) with self.assertRaises(TypeError): knxipframe.init(23)
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()
def test_EndTOEnd_group_write_2bytes(self): """Test parsing and streaming CEMIFrame KNX/IP packet, setting value of thermostat.""" # Incoming Temperature from thermostat raw = ((0x06, 0x10, 0x05, 0x30, 0x00, 0x13, 0x29, 0x00, 0xbc, 0xd0, 0x14, 0x02, 0x08, 0x01, 0x03, 0x00, 0x80, 0x07, 0xc1)) xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) knxipframe.from_knx(raw) telegram = knxipframe.body.cemi.telegram self.assertEqual( telegram, Telegram(GroupAddress("2049"), payload=DPTArray(DPTTemperature().to_knx(19.85)))) knxipframe2 = KNXIPFrame(xknx) knxipframe2.init(KNXIPServiceType.ROUTING_INDICATION) knxipframe2.body.cemi.src_addr = PhysicalAddress("1.4.2") knxipframe2.body.cemi.telegram = telegram knxipframe2.body.cemi.set_hops(5) knxipframe2.normalize() self.assertEqual(knxipframe2.header.to_knx(), list(raw[0:6])) self.assertEqual(knxipframe2.body.to_knx(), list(raw[6:])) self.assertEqual(knxipframe2.to_knx(), list(raw))
def test_connectionstate(self): """Test connectionstateing from KNX bus.""" xknx = XKNX(loop=self.loop) communication_channel_id = 23 udp_client = UDPClient(xknx, ("192.168.1.1", 0), ("192.168.1.2", 1234)) connectionstate = ConnectionState(xknx, udp_client, communication_channel_id) connectionstate.timeout_in_seconds = 0 self.assertEqual(connectionstate.awaited_response_class, ConnectionStateResponse) self.assertEqual(connectionstate.communication_channel_id, communication_channel_id) # Expected KNX/IP-Frame: exp_knxipframe = KNXIPFrame(xknx) exp_knxipframe.init(KNXIPServiceType.CONNECTIONSTATE_REQUEST) exp_knxipframe.body.communication_channel_id = communication_channel_id exp_knxipframe.body.control_endpoint = HPAI( ip_addr='192.168.1.3', port=4321) exp_knxipframe.normalize() 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(asyncio.Task(connectionstate.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: connectionstate.response_rec_callback(wrong_knxipframe, None) mock_warning.assert_called_with('Cant understand knxipframe') # Response KNX/IP-Frame with error: err_knxipframe = KNXIPFrame(xknx) err_knxipframe.init(KNXIPServiceType.CONNECTIONSTATE_RESPONSE) err_knxipframe.body.status_code = ErrorCode.E_CONNECTION_ID with patch('logging.Logger.warning') as mock_warning: connectionstate.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(connectionstate).__name__, type(err_knxipframe.body).__name__, ErrorCode.E_CONNECTION_ID) # Correct Response KNX/IP-Frame: res_knxipframe = KNXIPFrame(xknx) res_knxipframe.init(KNXIPServiceType.CONNECTIONSTATE_RESPONSE) with patch('logging.Logger.debug') as mock_debug: connectionstate.response_rec_callback(res_knxipframe, None) mock_debug.assert_called_with('Success: received correct answer from KNX bus: %s', ErrorCode.E_NO_ERROR) self.assertTrue(connectionstate.success)
def test_connect_request(self): """Test parsing and streaming connection tunneling request KNX/IP packet.""" raw = ((0x06, 0x10, 0x04, 0x20, 0x00, 0x15, 0x04, 0x01, 0x17, 0x00, 0x11, 0x00, 0xbc, 0xe0, 0x00, 0x00, 0x48, 0x08, 0x01, 0x00, 0x81)) xknx = XKNX(loop=self.loop) knxipframe = KNXIPFrame(xknx) knxipframe.from_knx(raw) self.assertTrue(isinstance(knxipframe.body, TunnellingRequest)) self.assertEqual(knxipframe.body.communication_channel_id, 1) self.assertEqual(knxipframe.body.sequence_counter, 23) self.assertTrue(isinstance(knxipframe.body.cemi, CEMIFrame)) self.assertEqual(knxipframe.body.cemi.telegram, Telegram(GroupAddress('9/0/8'), payload=DPTBinary(1))) knxipframe2 = KNXIPFrame(xknx) knxipframe2.init(KNXIPServiceType.TUNNELLING_REQUEST) knxipframe2.body.cemi.telegram = Telegram( GroupAddress('9/0/8'), payload=DPTBinary(1)) knxipframe2.body.sequence_counter = 23 knxipframe2.normalize() self.assertEqual(knxipframe2.to_knx(), list(raw))
def test_connection_state_request(self): """Test parsing and streaming connection state request KNX/IP packet.""" raw = ( 0x06, 0x10, 0x02, 0x07, 0x00, 0x10, 0x15, 0x00, 0x08, 0x01, 0xC0, 0xA8, 0xC8, 0x0C, 0xC3, 0xB4, ) xknx = XKNX() knxipframe = KNXIPFrame(xknx) knxipframe.from_knx(raw) self.assertTrue(isinstance(knxipframe.body, ConnectionStateRequest)) self.assertEqual(knxipframe.body.communication_channel_id, 21) self.assertEqual(knxipframe.body.control_endpoint, HPAI(ip_addr="192.168.200.12", port=50100)) knxipframe2 = KNXIPFrame(xknx) knxipframe2.init(KNXIPServiceType.CONNECTIONSTATE_REQUEST) knxipframe2.body.communication_channel_id = 21 knxipframe2.body.control_endpoint = HPAI(ip_addr="192.168.200.12", port=50100) knxipframe2.normalize() self.assertEqual(knxipframe2.to_knx(), list(raw))
async def test_connect_route_back_true(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=True) connect.timeout_in_seconds = 0 assert connect.awaited_response_class == ConnectResponse # Expected KNX/IP-Frame: exp_knxipframe = KNXIPFrame.init_from_body( ConnectRequest(xknx, request_type=ConnectRequestType.TUNNEL_CONNECTION)) 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) await 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) assert connect.success assert connect.communication_channel == 23 assert connect.identifier == 7