def _do_call(self, method_name_int, **kwargs):
        method = self._get_method(method_name_int)
        parsed_args = self._get_args(method, kwargs)
        file_path = "/www/api/methods/%s" % method["SCRIPT_FILE"]

        self.logger.debug("CALL: %s ARGS: %r", method["SCRIPT_FILE"], parsed_args)

        tcl = ""

        # Some of the methods use variables with same name but different types.
        # Since we use one continous running tclsh things get mixed up and cause
        # problems. Depending on which scripts are called. Some known vars are
        # cleaned up here. If this is too much trouble, switch to start/stop new
        # tclsh processes per call.
        tcl += "if { [info exists device] } {unset device}\n"
        tcl += "if { [info exists description] } {unset description}\n"

        # \0\n is written to stdout of the tclsh process to mark and detect the
        # end of the output of the API call.
        tcl += \
            "array set method $METHOD_LIST(%s)\n" \
            "array set args %s\n" \
            "source %s\n" \
            "puts \0\n" % (method["NAME"], parsed_args, file_path)

        self.logger.debug("  TCL: %r", tcl)

        self._tclsh.stdin.write(tcl.encode("utf-8"))

        response_txt = ""
        while True:
            line = self._tclsh.stdout.readline().decode("utf-8")
            if not line or (len(line) > 1 and line[-2] == "\0"):
                response_txt += line[:-2] + "\n"
                break # found our terminator (see above)
            else:
                response_txt += line

        self.logger.debug("  RESPONSE: %r", response_txt)
        # index 0 would be the header, but we don't need it
        body = response_txt.split("\n\n", 1)[1]

        try:
            return self._parse_api_response(method_name_int, kwargs, body)
        except PMException:
            self.logger.warning("Exception in API call.")
            self.logger.warning("  TCL: %r", tcl)
            self.logger.warning("  BODY: %r", body)
            raise