Ejemplo n.º 1
0
    def _receive(self) -> RSCPDTO:
        logger.debug("Waiting for response from " + str(self.ip))
        decrypted_data = None
        wait = 0.01
        while not decrypted_data:
            try:
                data = self.socket.recv(self.BUFFER_SIZE)
                logger.debug('Received ' + str(len(data)) + ' Bytes')
                if len(data) == 0:
                    self.socket.close()
                    raise RSCPCommunicationError(
                        "Did not receive data from e3dc", logger)
                self.rscp_utils = RSCPUtils()

                decrypted_data = self.encrypt_decrypt.decrypt(data)
            except BlockingIOError:
                logger.debug('Keine Daten empfangen, warte ' + str(wait) + 's')
                time.sleep(wait)
                wait *= 2
                if wait > 2:
                    raise

        #rawdata = binascii.hexlify(decrypted_data)
        #logger.debug('Response RAW: ' + str(rawdata))
        rscp_dto = self.rscp_utils.decode_data(decrypted_data)
        logger.debug("Received DTO Type: " + rscp_dto.type.name +
                     ", DTO Tag: " + rscp_dto.tag.name)
        return rscp_dto
Ejemplo n.º 2
0
 def __init__(self, username, password, ip, key):
     self.password = password
     self.username = username
     self.encrypt_decrypt = RSCPEncryptDecrypt(key)
     self.ip = ip
     self.socket = None
     self.rscp_utils = RSCPUtils()
Ejemplo n.º 3
0
 def __init__(self, username, password, ip, key):
     self.password = password
     self.username = username
     self.ip = ip
     self.socket = None
     self.key = key
     self.waittime = 0.01
     self.rscp_utils = RSCPUtils()
Ejemplo n.º 4
0
 def __init__(self, username, password, identifier, url = None):
     logger.debug('Initialisiere E3DC-Websockets')
     if not url:
         url = 'wss://s10.e3dc.com/ws'
     self.password = password
     self.username = username
     self.rscp_utils = RSCPUtils()
     self.identifier = identifier
     self.url = url
     logger.debug('Init abgeschlossen')
Ejemplo n.º 5
0
 def _receive(self) -> RSCPDTO:
     logger.info("Waiting for response from " + str(self.ip))
     data = self.socket.recv(self.BUFFER_SIZE)
     if len(data) == 0:
         self.socket.close()
         raise RSCPCommunicationError("Did not receive data from e3dc",
                                      logger)
     self.rscp_utils = RSCPUtils()
     decrypted_data = self.encrypt_decrypt.decrypt(data)
     rscp_dto = self.rscp_utils.decode_data(decrypted_data)
     logger.debug("Received DTO Type: " + rscp_dto.type.name +
                  ", DTO Tag: " + rscp_dto.tag.name)
     return rscp_dto
Ejemplo n.º 6
0
def test_decode_frame_raises_no_exception():
    rscp = RSCPUtils()
    hex_ = "e3dc" + \
           "1010" + \
           int.to_bytes(1564732130, length=8, byteorder=sys.byteorder).hex() + \
           int.to_bytes(94967295, length=4, byteorder=sys.byteorder).hex() + \
           int.to_bytes(256, length=2, byteorder=sys.byteorder).hex() + \
           bytearray(256).hex()
    checksum = zlib.crc32(bytes.fromhex(hex_))
    complete_hex = hex_ + int.to_bytes(
        checksum, length=4, byteorder=sys.byteorder).hex()
    data, timestamp = rscp._decode_frame(bytes.fromhex(complete_hex))
    assert timestamp == 1564827097.295
Ejemplo n.º 7
0
def test_decode_data_raises_checksum_exception():
    rscp = RSCPUtils()
    hex_ = "e3dc" + \
           "1010" + \
           int.to_bytes(1564732130, length=8, byteorder=sys.byteorder).hex() + \
           int.to_bytes(94967295, length=4, byteorder=sys.byteorder).hex() + \
           int.to_bytes(256, length=2, byteorder=sys.byteorder).hex() + \
           bytearray(256).hex()
    checksum = 156
    complete_hex = hex_ + int.to_bytes(
        checksum, length=4, byteorder=sys.byteorder).hex()
    with pytest.raises(RSCPFrameError):
        rscp.decode_data(bytes.fromhex(complete_hex))
Ejemplo n.º 8
0
def test_decode_data_returns_correct_value():
    rscp = RSCPUtils()
    hex_ = "e3dc" + \
           "1010" + \
           int.to_bytes(1564732130, length=8, byteorder=sys.byteorder).hex() + \
           int.to_bytes(94967295, length=4, byteorder=sys.byteorder).hex() + \
           int.to_bytes(11, length=2, byteorder=sys.byteorder).hex() + \
           "01000001" + "07" + struct.pack("<H", 4).hex() + struct.pack("<I", 98562).hex()
    checksum = zlib.crc32(bytes.fromhex(hex_))
    complete_hex = hex_ + int.to_bytes(
        checksum, length=4, byteorder=sys.byteorder).hex()
    rscp_dto = rscp.decode_data(bytes.fromhex(complete_hex))
    assert rscp_dto.tag == RSCPTag(0x01000001)
    assert rscp_dto.type == RSCPType(0x07)
    assert rscp_dto.data == 98562
Ejemplo n.º 9
0
def test_encrypted_frame_can_be_decrypted():
    encryptor = RSCPEncryptDecrypt("my_key")
    rscp_utils = RSCPUtils()
    encoded_data = rscp_utils.encode_data(
        RSCPDTO(RSCPTag.RSCP_REQ_AUTHENTICATION, RSCPType.Container, [
            RSCPDTO(RSCPTag.RSCP_AUTHENTICATION_USER, RSCPType.CString,
                    'username'),
            RSCPDTO(RSCPTag.RSCP_AUTHENTICATION_PASSWORD, RSCPType.CString,
                    'password')
        ]))
    framed_data = rscp_utils.encode_frame(encoded_data)
    encrypted_data = encryptor.encrypt(framed_data)
    decrypted_data = encryptor.decrypt(encrypted_data)
    redecoded_data = rscp_utils.decode_data(decrypted_data)
    assert redecoded_data.tag == RSCPTag.RSCP_REQ_AUTHENTICATION
    assert redecoded_data.type == RSCPType.Container
    assert len(redecoded_data.data) == 2
    assert redecoded_data.data[0].tag == RSCPTag.RSCP_AUTHENTICATION_USER
    assert redecoded_data.data[0].type == RSCPType.CString
    assert redecoded_data.data[0].data == 'username'
    assert redecoded_data.data[1].tag == RSCPTag.RSCP_AUTHENTICATION_PASSWORD
    assert redecoded_data.data[1].type == RSCPType.CString
    assert redecoded_data.data[1].data == 'password'
Ejemplo n.º 10
0
class E3DC:
    PORT = 5033
    BUFFER_SIZE = 1024 * 32

    def __init__(self, username, password, ip, key):
        self.password = password
        self.username = username
        self.ip = ip
        self.socket = None
        self.key = key
        self.waittime = 0.01
        self.rscp_utils = RSCPUtils()

    def create_encrypt(self):
        self.encrypt_decrypt = RSCPEncryptDecrypt(self.key)

    def send_requests2(self,
                       payload: [Union[RSCPDTO, RSCPTag]],
                       waittime=0.0) -> [RSCPDTO]:
        """
        This function will send a list of requests consisting of RSCPDTO's oder RSCPTag's to the e3dc
        and returns a list of responses.

        i.e. responses = send_requests([RSCPTag.EMS_REQ_BAT_SOC, RSCPTag.EMS_REQ_POWER_PV,
                                            RSCPTag.EMS_REQ_POWER_BAT, RSCPTag.EMS_REQ_POWER_GRID,
                                            RSCPTag.EMS_REQ_POWER_WB_ALL])
        :param payload: A list of requests
        :return: A list of responses in form of RSCPDTO's
        """
        dto_list: [RSCPDTO] = []
        for payload_element in payload:
            if isinstance(payload_element, RSCPTag):
                dto_list.append(RSCPDTO(payload_element))
            else:
                dto_list.append(payload_element)
        logger.debug("Sending " + str(len(dto_list)) + " requests to " +
                     str(self.ip))
        responses: [RSCPDTO] = []
        dto: RSCPDTO
        for dto in dto_list:
            response = self.send_request(dto, True, waittime=waittime)
            responses.append(response)
        return responses

    def send_requests(self,
                      payload: [Union[RSCPDTO, RSCPTag]],
                      waittime=0.0) -> [RSCPDTO]:
        payload_all = bytes()
        for payload_element in payload:
            if isinstance(payload_element, RSCPTag):
                dto = RSCPDTO(payload_element)
            else:
                dto = payload_element

            payload_all += self.rscp_utils.encode_data(dto)

        prepared_data = self.rscp_utils.encode_frame(payload_all)
        response = self.send_request(prepared_data, True, waittime)

        responses: [RSCPDTO] = []
        if response.type == RSCPType.Container:
            data: RSCPDTO
            for data in response:
                responses.append(data)
        else:
            responses.append(response)

        return responses

    def send_request(self,
                     payload: Union[RSCPDTO, RSCPTag, bytes],
                     keep_connection_alive: bool = False,
                     waittime: float = 0.0) -> RSCPDTO:
        """
        This will perform a single request.

        :param payload: The payload that defines the request
        :param keep_connection_alive: A flag whether to keep the connection alive or not
        :return: A response object as RSCPDTO
        """
        if isinstance(payload, RSCPTag):
            payload = RSCPDTO(payload)
        if self.socket is None:
            self._connect()

        if isinstance(payload, bytes):
            prepared_data = payload
        else:
            encode_data = self.rscp_utils.encode_data(payload)
            prepared_data = self.rscp_utils.encode_frame(encode_data)

        #rawdata = binascii.hexlify(prepared_data)
        #logger.debug('Send RAW: ' + str(rawdata))
        logger.debug('Send ' + str(len(prepared_data)) + ' Bytes')
        encrypted_data = self.encrypt_decrypt.encrypt(prepared_data)
        try:
            self.socket.send(encrypted_data)
        except:
            self._disconnect()
            raise

        wait = self.waittime + waittime
        if wait > 0.0:
            time.sleep(wait)

        response = self._receive()
        if response.type == RSCPType.Error:
            logger.debug("Error type returned: " + str(response.data))
            raise (RSCPCommunicationError(
                'Error type returned: ' + str(response.data), logger,
                response))
        if not keep_connection_alive:
            self._disconnect()
        return response

    def _connect(self):
        if self.socket is None:
            logger.info("Trying to establish connection to " + str(self.ip))
            self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.socket.connect((self.ip, self.PORT))
            self.socket.setblocking(False)
            rscp_dto = RSCPDTO(
                RSCPTag.RSCP_REQ_AUTHENTICATION, RSCPType.Container, [
                    RSCPDTO(RSCPTag.RSCP_AUTHENTICATION_USER, RSCPType.CString,
                            self.username),
                    RSCPDTO(RSCPTag.RSCP_AUTHENTICATION_PASSWORD,
                            RSCPType.CString, self.password)
                ], None)
            self.create_encrypt()
            result = self.send_request(rscp_dto, True)
            if result.type == RSCPType.Error:
                self._disconnect()
                raise RSCPAuthenticationError("Invalid username or password",
                                              logger)

    def _disconnect(self):
        logger.info("Closing connection to " + str(self.ip))
        self.socket.close()
        self.socket = None

    def _receive(self) -> RSCPDTO:
        logger.debug("Waiting for response from " + str(self.ip))
        decrypted_data = None
        wait = 0.01
        while not decrypted_data:
            try:
                data = self.socket.recv(self.BUFFER_SIZE)
                logger.debug('Received ' + str(len(data)) + ' Bytes')
                if len(data) == 0:
                    self.socket.close()
                    raise RSCPCommunicationError(
                        "Did not receive data from e3dc", logger)
                self.rscp_utils = RSCPUtils()

                decrypted_data = self.encrypt_decrypt.decrypt(data)
            except BlockingIOError:
                logger.debug('Keine Daten empfangen, warte ' + str(wait) + 's')
                time.sleep(wait)
                wait *= 2
                if wait > 2:
                    raise

        #rawdata = binascii.hexlify(decrypted_data)
        #logger.debug('Response RAW: ' + str(rawdata))
        rscp_dto = self.rscp_utils.decode_data(decrypted_data)
        logger.debug("Received DTO Type: " + rscp_dto.type.name +
                     ", DTO Tag: " + rscp_dto.tag.name)
        return rscp_dto
Ejemplo n.º 11
0
class E3DCWeb(E3DC):
    def __init__(self, username, password, identifier, url = None):
        logger.debug('Initialisiere E3DC-Websockets')
        if not url:
            url = 'wss://s10.e3dc.com/ws'
        self.password = password
        self.username = username
        self.rscp_utils = RSCPUtils()
        self.identifier = identifier
        self.url = url
        logger.debug('Init abgeschlossen')

    lasterror = None
    conid = None

    server_connection_id = None
    server_auth_level = None
    info_serial_number = None
    server_type = None
    ws = None

    next_response = None
    next_response_data = None

    def get_connected(self):
        if self.server_auth_level == 10 and self.server_connection_id and self.server_auth_level and self.identifier and self.conid:
            return True
        else:
            return False

    def set_connected(self, value):
        if value == False:
            self.server_auth_level = None
            self.server_connection_id = None
            self.server_auth_level = None
            self.ws = None
            self.server_type = None
            self.conid = None

    connected = property(get_connected, set_connected)


    def register_next_response(self):
        self.next_response = True
        self.next_response_data = None

    def getWeblogin(self):
        r = RSCPDTO(RSCPTag.SERVER_REQ_NEW_VIRTUAL_CONNECTION, rscp_type=RSCPType.Container)

        r += RSCPDTO(RSCPTag.SERVER_USER, RSCPType.CString, self.username)
        pass_md5 = hashlib.md5()
        pass_md5.update(self.password.encode('utf-8'))
        password = pass_md5.hexdigest()
        r += RSCPDTO(RSCPTag.SERVER_PASSWD, RSCPType.CString, password)

        r += RSCPDTO(RSCPTag.SERVER_IDENTIFIER, RSCPType.CString, self.identifier)
        r += RSCPDTO(RSCPTag.SERVER_TYPE, RSCPType.Int32, 4)
        r += RSCPDTO(RSCPTag.SERVER_HASH_CODE, RSCPType.Int32, 1234567890)

        return [r]

    def interpreter_serverdata(self, data):
        if not isinstance(data, list):
            data = [data]

        requests = []
        for res in data:
            if res.name == 'SERVER_REGISTER_CONNECTION':
                logger.debug(res.name)
                self.server_connection_id = res['SERVER_CONNECTION_ID'].data
                self.server_auth_level = res['SERVER_AUTH_LEVEL'].data
                self.server_type = res['SERVER_TYPE'].data

                r = RSCPDTO(tag=RSCPTag.SERVER_CONNECTION_REGISTERED, rscp_type=RSCPType.Container)

                r += RSCPDTO(tag=RSCPTag.SERVER_CONNECTION_ID, rscp_type=RSCPType.Int64,
                             data=self.server_connection_id)
                r += RSCPDTO(tag=RSCPTag.SERVER_AUTH_LEVEL, rscp_type=RSCPType.UChar8,
                             data=self.server_auth_level)
                requests.append(r)

            if res.name == 'SERVER_UNREGISTER_CONNECTION':
                logger.debug(res.name)
                self.server_connection_id = None
                self.server_auth_level = None
                r = self.getWeblogin()
                requests += r

            elif res.name == 'SERVER_REQ_RSCP_CMD':
                if res['SERVER_RSCP_DATA']:
                    p = []
                    rscp_data = res['SERVER_RSCP_DATA']

                    if self.next_response:
                        if isinstance(rscp_data.data, RSCPDTO):
                            self.next_response_data = rscp_data.data
                        else:
                            self.next_response_data = rscp_data
                        self.next_response = None
                    if 'INFO_SERIAL_NUMBER' in rscp_data:
                        self.info_serial_number = rscp_data['INFO_SERIAL_NUMBER'].data

                    if 'INFO_REQ_IP_ADDRESS' in rscp_data:
                        p.append(RSCPDTO(RSCPTag.INFO_IP_ADDRESS, rscp_type=RSCPType.CString, data='0.0.0.0'))
                    if 'INFO_REQ_SUBNET_MASK' in rscp_data:
                        p.append(RSCPDTO(RSCPTag.INFO_SUBNET_MASK, rscp_type=RSCPType.CString, data='0.0.0.0'))
                    if 'INFO_REQ_GATEWAY' in rscp_data:
                        p.append(RSCPDTO(RSCPTag.INFO_GATEWAY, rscp_type=RSCPType.CString, data='0.0.0.0'))
                    if 'INFO_REQ_DNS' in rscp_data:
                        p.append(RSCPDTO(RSCPTag.INFO_DNS, rscp_type=RSCPType.CString, data='0.0.0.0'))
                    if 'INFO_REQ_DHCP_STATUS' in rscp_data:
                        p.append(RSCPDTO(RSCPTag.INFO_DHCP_STATUS, rscp_type=RSCPType.Bool, data=False))

                    if 'INFO_REQ_TIME' in rscp_data:
                        # TODO: Zeitstempel korrekt bilden mit Berücksichtigung der Zeitzone
                        current_time = time.time()
                        seconds = math.ceil(current_time)
                        nanoseconds = round((current_time - int(current_time)) * 1000)
                        ts = struct.pack('<QI', seconds, nanoseconds)

                        p.append(RSCPDTO(RSCPTag.INFO_TIME, rscp_type=RSCPType.ByteArray, data=ts))
                    if 'INFO_REQ_TIME_ZONE' in rscp_data:
                        p.append(RSCPDTO(RSCPTag.INFO_TIME_ZONE, rscp_type=RSCPType.CString, data='GMT+2'))

                    if 'INFO_REQ_UTC_TIME' in rscp_data:
                        current_time = time.time() + 7200
                        seconds = math.ceil(current_time)
                        nanoseconds = round((current_time - int(current_time)) * 1000)
                        ts = struct.pack('<QI', seconds, nanoseconds)

                        p.append(RSCPDTO(RSCPTag.INFO_UTC_TIME, rscp_type=RSCPType.ByteArray, data=ts))

                    if 'INFO_REQ_A35_SERIAL_NUMBER' in rscp_data:
                        p.append(RSCPDTO(RSCPTag.INFO_A35_SERIAL_NUMBER, rscp_type=RSCPType.CString, data='123456'))

                    if 'INFO_REQ_INFO' in rscp_data:
                        info = RSCPDTO(RSCPTag.INFO_INFO, rscp_type=RSCPType.Container)
                        hsh = self.username + str(self.server_connection_id)
                        md5 = hashlib.md5(hsh.encode()).hexdigest()
                        info += RSCPDTO(RSCPTag.INFO_SERIAL_NUMBER, rscp_type=RSCPType.CString, data='WEB_' + md5)
                        info += RSCPDTO(RSCPTag.INFO_MAC_ADDRESS, rscp_type=RSCPType.CString, data='00:00:00:00:00:00')
                        p.append(info)

                    if len(p) > 0:
                        requests.append(self.getRSCPToServer(p))

            elif res.name == 'SERVER_REQ_PING':
                logger.debug(res.name)
                r = RSCPDTO(tag=RSCPTag.SERVER_PING)
                requests.append(r)

        return requests

    def getRSCPToServer(self, p):
        if not isinstance(p, list):
            p = [p]

        payload = b''
        for payload_element in p:
            if isinstance(payload_element, RSCPTag):
                x = RSCPDTO(payload_element)
            else:
                x = payload_element
            payload += self.rscp_utils.encode_data(x)

        payload = self.rscp_utils.encode_frame(payload)

        r = RSCPDTO(tag=RSCPTag.SERVER_REQ_RSCP_CMD, rscp_type=RSCPType.Container)
        r += RSCPDTO(tag=RSCPTag.SERVER_CONNECTION_ID, rscp_type=RSCPType.Int64, data=self.server_connection_id)
        r += RSCPDTO(tag=RSCPTag.SERVER_AUTH_LEVEL, rscp_type=RSCPType.UChar8, data=self.server_auth_level)
        r += RSCPDTO(tag=RSCPTag.SERVER_RSCP_DATA_LEN, rscp_type=RSCPType.Int32, data=len(payload))
        r += RSCPDTO(tag=RSCPTag.SERVER_RSCP_DATA, rscp_type=RSCPType.ByteArray, data=payload)
        return r

    def send_data(self, r, ws = None, waittime=None):
        if not ws:
            ws = self.ws
        dataframe = self.rscp_utils.encode_data(r)
        bindat = self.rscp_utils.encode_frame(dataframe, crc=True)
        logger.debug('Sende Daten ' + str(len(bindat)))
        ws.send(bindat, websocket.ABNF.OPCODE_BINARY)

    def close_ws(self):
        if self.ws and self.conid:
            self.ws.close()


    def start_ws(self):
        if self.connected:
            conid = 'ConID: ' + self.conid
            logger.warning(conid + ' - Websocket-Verbindung besteht bereits, eine erneute Verbindung ist nicht möglich')
            return False

        self.conid = str(round(time.time(),2))
        conid = 'ConID: ' + self.conid

        def on_message(ws, message):
            try:
                data = self.rscp_utils.decode_server_data(message)
                res = self.interpreter_serverdata(data)
                for r in res:
                    self.send_data(r, ws)
                self.lasterror = None
            except Exception as e:
                self.lasterror = e
                logger.exception(conid + ' - Fehler beim Verarbeiten der Daten : ' + str(e))

        def on_error(ws, error):
            self.lasterror = error
            logger.error(conid + ' - Verbindungsfehler ' + str(error))

        def on_close(ws):
            self.lasterror = 'Connection closed'
            self.connected = False
            logger.info(conid + ' - Verbindung geschlossen')

        #websocket.enableTrace(True)
        ws = websocket.WebSocketApp(self.url,
                                    on_message=on_message,
                                    on_error=on_error,
                                    on_close=on_close)

        self.ws = ws
        logger.debug(conid + ' - Starte Websocket-Verbindung mit ' + self.url)
        ws.run_forever()
        logger.debug(conid + ' - Websocket-Verbindung beendet')
        self.conid = None

    def __del__(self):
        self.ws.close()
Ejemplo n.º 12
0
class E3DC:
    PORT = 5033
    BUFFER_SIZE = 1024 * 32

    def __init__(self, username, password, ip, key):
        self.password = password
        self.username = username
        self.encrypt_decrypt = RSCPEncryptDecrypt(key)
        self.ip = ip
        self.socket = None
        self.rscp_utils = RSCPUtils()

    def send_requests(self, paylod: [Union[RSCPDTO, RSCPTag]]) -> [RSCPDTO]:
        """
        This function will send a list of requests consisting of RSCPDTO's oder RSCPTag's to the e3dc
        and returns a list of responses.

        i.e. responses = send_requests([RSCPTag.EMS_REQ_BAT_SOC, RSCPTag.EMS_REQ_POWER_PV,
                                            RSCPTag.EMS_REQ_POWER_BAT, RSCPTag.EMS_REQ_POWER_GRID,
                                            RSCPTag.EMS_REQ_POWER_WB_ALL])
        :param paylod: A list of requests
        :return: A list of responses in form of RSCPDTO's
        """
        dto_list: [RSCPDTO] = []
        for payload_element in paylod:
            if isinstance(payload_element, RSCPTag):
                dto_list.append(RSCPDTO(payload_element))
            else:
                dto_list.append(payload_element)
        logger.info("Sending " + str(len(dto_list)) + " requests to " +
                    str(self.ip))
        responses: [RSCPDTO] = []
        dto: RSCPDTO
        for dto in dto_list:
            responses.append(self.send_request(dto, True))
        return responses

    def send_request(self,
                     payload: Union[RSCPDTO, RSCPTag],
                     keep_connection_alive: bool = False) -> RSCPDTO:
        """
        This will perform a single request.

        :param payload: The payload that defines the request
        :param keep_connection_alive: A flag whether to keep the connection alive or not
        :return: A response object as RSCPDTO
        """
        if isinstance(payload, RSCPTag):
            payload = RSCPDTO(payload)
        if self.socket is None:
            self._connect()
        encode_data = self.rscp_utils.encode_data(payload)
        prepared_data = self.rscp_utils.encode_frame(encode_data)
        encrypted_data = self.encrypt_decrypt.encrypt(prepared_data)
        self.socket.send(encrypted_data)
        response = self._receive()
        if response.type == RSCPType.Error:
            logger.error("Error type returned")
            raise (RSCPCommunicationError(None, logger))
        if not keep_connection_alive:
            self._disconnect()
        return response

    def _connect(self):
        if self.socket is None:
            logger.info("Trying to establish connection to " + str(self.ip))
            self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.socket.connect((self.ip, self.PORT))
            rscp_dto = RSCPDTO(
                RSCPTag.RSCP_REQ_AUTHENTICATION, RSCPType.Container, [
                    RSCPDTO(RSCPTag.RSCP_AUTHENTICATION_USER, RSCPType.CString,
                            self.username),
                    RSCPDTO(RSCPTag.RSCP_AUTHENTICATION_PASSWORD,
                            RSCPType.CString, self.password)
                ], None)
            result = self.send_request(rscp_dto, True)
            if result.type == RSCPType.Error:
                self._disconnect()
                raise RSCPAuthenticationError("Invalid username or password",
                                              logger)

    def _disconnect(self):
        logger.info("Closing connection to " + str(self.ip))
        self.socket.close()
        self.socket = None

    def _receive(self) -> RSCPDTO:
        logger.info("Waiting for response from " + str(self.ip))
        data = self.socket.recv(self.BUFFER_SIZE)
        if len(data) == 0:
            self.socket.close()
            raise RSCPCommunicationError("Did not receive data from e3dc",
                                         logger)
        self.rscp_utils = RSCPUtils()
        decrypted_data = self.encrypt_decrypt.decrypt(data)
        rscp_dto = self.rscp_utils.decode_data(decrypted_data)
        logger.debug("Received DTO Type: " + rscp_dto.type.name +
                     ", DTO Tag: " + rscp_dto.tag.name)
        return rscp_dto