docs: def execute(self, uri, namespace, action, timeout=2, **kwargs):
          """Executes a given action with optional arguments.
  
          The execution of an action of an UPnP/TR64 device needs more than just the name of an action. It needs the
          control URI which is called to place the action and also the namespace aka service type is needed. The
          namespace defines the scope or service type of the given action, the same action name can appear in different
          namespaces.
  
          The way how to obtain the needed information's is either through the documentation of the vendor of the
          device. Or through a discovery requests which return's the URL to the root device description XML.
  
          :param str uri: the control URI, for example ``/upnp/control/hosts``
          :param str namespace: the namespace for the given action, for example ``urn:dslforum-org:service:Hosts:1``
          :param str action: the name of the action to call, for example ``GetGenericHostEntry``
          :param float timeout: the timeout to wait for the action to be executed
          :param kwargs: optional arguments for the given action, depends if the action needs parameter. The arguments
              are given as dict where the key is the parameter name and the value the value of the parameter.
          :type kwargs: dict[str, str]
          :return: returns the results of the action, if any. The results are structured as dict where the key is the
              name of the result argument and the value is the value of the result.
          :rtype: dict[str,str]
          :raises ValueError: if parameters are not set correctly
          :raises requests.exceptions.ConnectionError: when the action can not be placed on the device
          :raises requests.exceptions.ConnectTimeout: when download time out
  
          Example:
  
          ::
  
              device = DeviceTR64(...)
              device.execute("/upnp/control/hosts", "urn:dslforum-org:service:Hosts:1",
                  "GetGenericHostEntry", {"NewIndex": 1})
              {'NewActive': '0', 'NewIPAddress': '192.168.0.23', 'NewMACAddress': '9C:20:7B:E7:FF:5F',
                  'NewInterfaceType': 'Ethernet', 'NewHostName': 'Apple-TV', 'NewAddressSource': 'DHCP',
                  'NewLeaseTimeRemaining': '0'}
  
          .. seealso::
  
              `Additional short explanation of the UPnP protocol <http://www.upnp-hacks.org/upnp.html>`_
  
              :class:`~simpletr64.Discover`, :meth:`~simpletr64.DeviceTR64.loadDeviceDefinitions`,
              :meth:`~simpletr64.DeviceTR64.loadSCPD`
          """
  
          if not uri:
              raise ValueError("No action URI has been defined.")
  
          if not namespace:
              raise ValueError("No namespace has been defined.")
  
          if not action:
              raise ValueError("No action has been defined.")
  
          # soap headers
          header = {'Content-Type': 'text/xml; charset="UTF-8"',
                    'Soapaction': '"' + namespace + "#" + action + '"'}
  
          # build SOAP body
          body = '''<?xml version="1.0" encoding="UTF-8"?>
  <s:Envelope
      s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
      xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
      xmlns:xsd="http://www.w3.org/2001/XMLSchema"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <s:Header/>
      <s:Body>\n'''
  
          body += "        <u:" + action + ' xmlns="' + namespace + '">\n'
  
          arguments = {}
  
          for key in kwargs.keys():
              body += "            <" + key + ">" + str(kwargs[key]) + "</" + key + ">\n"
              arguments[key] = str(kwargs[key])
  
          body += "        </u:" + action + ">\n"
          body += '''</s:Body>
  </s:Envelope>'''
  
          # setup proxies
          proxies = {}
          if self.__httpsProxy:
              proxies = {"https": self.__httpsProxy}
  
          if self.__httpProxy:
              proxies = {"http": self.__httpProxy}
  
          # setup authentication
          auth = None
          if self.__password:
              auth = HTTPDigestAuth(self.__username, self.__password)
  
          # build the URL
          location = self.__protocol + "://" + self.__hostname + ":" + str(self.port) + uri
  
          # Post http request
          request = requests.post(location, data=body, headers=header, auth=auth, proxies=proxies, timeout=float(timeout),
                                 verify=self.__verify)
  
          if request.status_code != 200:
              errorStr = DeviceTR64._extractErrorString(request)
              raise ValueError('Could not execute "' + action + str(arguments) + '": ' + str(request.status_code) +
                               ' - ' + request.reason + " -- " + errorStr)
  
          # parse XML return
          try:
              root = ET.fromstring(request.text.encode('utf-8'))
          except Exception as e:
              raise ValueError("Can not parse results for the action: " + str(e))
  
          # iterate in the XML structure to get the action result
          actionNode = root[0][0]
  
          # we need to remove XML namespace for the action node
          namespaceLength = len(namespace) + 2  # add braces
          tag = actionNode.tag[namespaceLength:]
  
          if tag != (action + "Response"):
              raise ValueError('Soap result structure is wrong, expected action "' + action +
                               'Response" got "' + tag + '".')
  
          # pack all the received results
          results = {}
  
          for resultNode in actionNode:
              results[resultNode.tag] = resultNode.text
  
          return results