Example #1
0
def printerSdCommand():
	if not settings().getBoolean(["feature", "sdSupport"]):
		return make_response("SD support is disabled", 404)

	if not printer.is_operational() or printer.is_printing() or printer.is_paused():
		return make_response("Printer is not operational or currently busy", 409)

	valid_commands = {
		"init": [],
		"refresh": [],
		"release": []
	}
	command, data, response = get_json_command_from_request(request, valid_commands)
	if response is not None:
		return response

	tags = {"source:api", "api:printer.sd"}

	if command == "init":
		printer.init_sd_card(tags=tags)
	elif command == "refresh":
		printer.refresh_sd_files(tags=tags)
	elif command == "release":
		printer.release_sd_card(tags=tags)

	return NO_CONTENT
Example #2
0
def printerState():
    if not printer.is_operational():
        return make_response("Printer is not operational", 409)

    # process excludes
    excludes = []
    if "exclude" in request.values:
        excludeStr = request.values["exclude"]
        if len(excludeStr.strip()) > 0:
            excludes = [
                x for x in [x.strip() for x in excludeStr.split(",")]
                if x in ["temperature", "sd", "state"]
            ]

    result = {}

    processor = lambda x: x
    if not printerProfileManager.get_current_or_default()["heatedBed"]:
        processor = _delete_bed

    # add temperature information
    if not "temperature" in excludes:
        result.update({"temperature": _get_temperature_data(processor)})

    # add sd information
    if not "sd" in excludes and settings().getBoolean(["feature", "sdSupport"
                                                       ]):
        result.update({"sd": {"ready": printer.is_sd_ready()}})

    # add state information
    if not "state" in excludes:
        state = printer.get_current_data()["state"]
        result.update({"state": state})

    return jsonify(result)
Example #3
0
def printerState():
	if not printer.is_operational():
		return make_response("Printer is not operational", 409)

	# process excludes
	excludes = []
	if "exclude" in request.values:
		excludeStr = request.values["exclude"]
		if len(excludeStr.strip()) > 0:
			excludes = filter(lambda x: x in ["temperature", "sd", "state"], map(lambda x: x.strip(), excludeStr.split(",")))

	result = {}

	# add temperature information
	if not "temperature" in excludes:
		result.update({"temperature": _getTemperatureData(lambda x: x)})

	# add sd information
	if not "sd" in excludes and settings().getBoolean(["feature", "sdSupport"]):
		result.update({"sd": {"ready": printer.is_sd_ready()}})

	# add state information
	if not "state" in excludes:
		state = printer.get_current_data()["state"]
		result.update({"state": state})

	return jsonify(result)
Example #4
0
def printMemoryFile():
	if not printer.is_operational():
		return make_response("Printer is not operational", 409)

	printer.printFromMemory()

	return NO_CONTENT
Example #5
0
def getNozzlesAndFilament():
    """
	Returns the list of available nozzles, the current selected nozzle, the current selected filament
	and the amount of filament left in spool
	:return:
	"""
    nozzle_list = s().get(["nozzleTypes"])

    if not printer.is_operational():
        return jsonify({
            "nozzle": '0.4',
            "nozzleList": nozzle_list,
            "filament": 'A023 - Black',
            "filamentInSpool": 0.0
        })

    filament = printer.getFilamentString()
    filamentInSpool = printer.getFilamentWeightInSpool()
    nozzle = printer.getNozzleSize()
    # converts the nozzle size to float
    nozzle = float(nozzle) / 1000.0

    return jsonify({
        "nozzle": nozzle,
        "nozzleList": nozzle_list,
        "filament": filament,
        "filamentInSpool": filamentInSpool
    })
Example #6
0
def controlTeste():
	if not printer.is_operational():
		return make_response("Printer is not operational", 409)
		
	activePrintjob = printer.is_printing() or printer.is_paused()
	
	printer.cancel_teste()
Example #7
0
def getFilamentInSpool():
    if not printer.is_operational():
        return make_response("Printer is not operational", 409)

    resp = printer.getFilamentWeightInSpool()

    return jsonify({"filament": resp})
Example #8
0
def controlJob():
	if not printer.is_operational():
		return make_response("Printer is not operational", 409)

	valid_commands = {
		"start": [],
		"restart": [],
		"pause": [],
		"cancel": []
	}

	command, data, response = get_json_command_from_request(request, valid_commands)
	if response is not None:
		return response

	activePrintjob = printer.is_printing() or printer.is_paused()

	if command == "start":
		if activePrintjob:
			return make_response("Printer already has an active print job, did you mean 'restart'?", 409)
		printer.start_print()
	elif command == "restart":
		if not printer.is_paused():
			return make_response("Printer does not have an active print job or is not paused", 409)
		printer.start_print()
	elif command == "pause":
		if not activePrintjob:
			return make_response("Printer is neither printing nor paused, 'pause' command cannot be performed", 409)
		printer.toggle_pause_print()
	elif command == "cancel":
		if not activePrintjob:
			return make_response("Printer is neither printing nor paused, 'cancel' command cannot be performed", 409)
		printer.cancel_print()
	return NO_CONTENT
Example #9
0
def heatingDone():
    if not printer.is_operational():
        return make_response("Printer is not operational", 409)

    printer.heatingDone()

    return NO_CONTENT
Example #10
0
def getNozzleList():
    if not printer.is_operational():
        return make_response("Printer is not operational", 409)

    resp = printer.getNozzleTypes()

    return jsonify({"nozzles": resp})
Example #11
0
def saveNozzle():

    if not printer.is_operational():
        return make_response("Printer is not operational", 409)

    valid_commands = {"nozzle": ["nozzleType"]}
    command, data, response = get_json_command_from_request(
        request, valid_commands)
    if response is not None:
        return response

    nozzle = data['nozzleType']

    if not printer.isValidNozzleSize(nozzle):
        return make_response("Invalid nozzle size", 409)

    # converts the nozzle to integer
    nozzle = int(nozzle * 1000)
    resp = printer.setNozzleSize(nozzle)

    printer_profile = printerProfileManager.get_current()
    if printer_profile is not None:
        printer_profile['extruder']['nozzleDiameter'] = nozzle
        printerProfileManager.save(printer_profile, allow_overwrite=True)
    else:
        return jsonify(
            {"response": "Could not find printer profile for saving."})

    return jsonify({"response": resp})
Example #12
0
def getSystemInfo():
    from octoprint.cli.systeminfo import get_systeminfo
    from octoprint.server import (
        connectivityChecker,
        environmentDetector,
        printer,
        safe_mode,
    )
    from octoprint.util import dict_flatten

    systeminfo = get_systeminfo(
        environmentDetector,
        connectivityChecker,
        {
            "browser.user_agent": request.headers.get("User-Agent"),
            "octoprint.safe_mode": safe_mode is not None,
            "systeminfo.generator": "systemapi",
        },
    )

    if printer and printer.is_operational():
        firmware_info = printer.firmware_info
        if firmware_info:
            systeminfo.update(
                dict_flatten({"firmware": firmware_info["name"]},
                             prefix="printer"))

    return jsonify(systeminfo=systeminfo)
Example #13
0
def controlJob():
	if not printer.is_operational():
		return make_response("Printer is not operational", 409)

	valid_commands = {
		"start": [],
		"restart": [],
		"pause": [],
		"cancel": []
	}

	command, data, response = get_json_command_from_request(request, valid_commands)
	if response is not None:
		return response

	activePrintjob = printer.is_printing() or printer.is_paused()

	if command == "start":
		if activePrintjob:
			return make_response("Printer already has an active print job, did you mean 'restart'?", 409)
		printer.start_print()
	elif command == "restart":
		if not printer.is_paused():
			return make_response("Printer does not have an active print job or is not paused", 409)
		printer.start_print()
	elif command == "pause":
		if not activePrintjob:
			return make_response("Printer is neither printing nor paused, 'pause' command cannot be performed", 409)
		printer.toggle_pause_print()
	elif command == "cancel":
		if not activePrintjob:
			return make_response("Printer is neither printing nor paused, 'cancel' command cannot be performed", 409)
		printer.cancel_print()
	return NO_CONTENT
Example #14
0
def controlJob():
    if not printer.is_operational():
        abort(409, description="Printer is not operational")

    valid_commands = {"start": [], "restart": [], "pause": [], "cancel": []}

    command, data, response = get_json_command_from_request(
        request, valid_commands)
    if response is not None:
        return response

    activePrintjob = printer.is_printing() or printer.is_paused()

    tags = {"source:api", "api:job"}

    user = current_user.get_name()

    with Permissions.PRINT.require(403):
        if command == "start":
            if activePrintjob:
                abort(
                    409,
                    description=
                    "Printer already has an active print job, did you mean 'restart'?",
                )
            printer.start_print(tags=tags, user=user)
        elif command == "restart":
            if not printer.is_paused():
                abort(
                    409,
                    description=
                    "Printer does not have an active print job or is not paused",
                )
            printer.start_print(tags=tags, user=user)
        elif command == "pause":
            if not activePrintjob:
                abort(
                    409,
                    description=
                    "Printer is neither printing nor paused, 'pause' command cannot be performed",
                )
            action = data.get("action", "toggle")
            if action == "toggle":
                printer.toggle_pause_print(tags=tags, user=user)
            elif action == "pause":
                printer.pause_print(tags=tags, user=user)
            elif action == "resume":
                printer.resume_print(tags=tags, user=user)
            else:
                abort(400, description="Unknown action")
        elif command == "cancel":
            if not activePrintjob:
                abort(
                    409,
                    description=
                    "Printer is neither printing nor paused, 'cancel' command cannot be performed",
                )
            printer.cancel_print(tags=tags, user=user)
    return NO_CONTENT
Example #15
0
def printerCommand():
    if not printer.is_operational():
        return make_response("Printer is not operational", 409)

    if "application/json" not in request.headers["Content-Type"]:
        return make_response("Expected content type JSON", 400)

    try:
        data = request.get_json()
    except BadRequest:
        return make_response("Malformed JSON body in request", 400)

    if data is None:
        return make_response("Malformed JSON body in request", 400)

    if "command" in data and "commands" in data:
        return make_response("'command' and 'commands' are mutually exclusive", 400)
    elif ("command" in data or "commands" in data) and "script" in data:
        return make_response(
            "'command'/'commands' and 'script' are mutually exclusive", 400
        )
    elif not ("command" in data or "commands" in data or "script" in data):
        return make_response("Need one of 'command', 'commands' or 'script'", 400)

    parameters = {}
    if "parameters" in data:
        parameters = data["parameters"]

    tags = {"source:api", "api:printer.command"}

    if "command" in data or "commands" in data:
        if "command" in data:
            commands = [data["command"]]
        else:
            if not isinstance(data["commands"], (list, tuple)):
                return make_response("'commands' needs to be a list", 400)
            commands = data["commands"]

        commandsToSend = []
        for command in commands:
            commandToSend = command
            if len(parameters) > 0:
                commandToSend = command % parameters
            commandsToSend.append(commandToSend)

        printer.commands(commandsToSend, tags=tags)

    elif "script" in data:
        script_name = data["script"]
        context = {"parameters": parameters}
        if "context" in data:
            context["context"] = data["context"]

        try:
            printer.script(script_name, context=context, tags=tags)
        except UnknownScript:
            return make_response("Unknown script: {script_name}".format(**locals()), 404)

    return NO_CONTENT
Example #16
0
def nextCalibrationStep():

    if not printer.is_operational():
        return make_response("Printer is not operational", 409)

    printer.nextCalibrationStep()

    return NO_CONTENT
Example #17
0
def startCalibration():

    if not printer.is_operational():
        return make_response("Printer is not operational", 409)

    printer.startCalibration()

    return NO_CONTENT
Example #18
0
def loadFilament():

    if not printer.is_operational():
        return make_response("Printer is not operational", 409)

    printer.load()

    return NO_CONTENT
Example #19
0
def cancelHeating():

    if not printer.is_operational():
        return make_response("Printer is not operational", 409)

    printer.cancelHeating()

    return NO_CONTENT
Example #20
0
def startHeating():
    if not printer.is_operational():
        return make_response("Printer is not operational", 409)

    printer.startHeating(
    )  # In the future we might pass the extruder identifier here in case of more than 1 extruder

    return NO_CONTENT
Example #21
0
def inCalibrationTest():

    if not printer.is_operational():
        return make_response("Printer is not operational", 409)

    res = printer.isRunningCalibrationTest()

    return jsonify({"response": res})
Example #22
0
def getSavedNozzle():
    if not printer.is_operational():
        return make_response("Printer is not operational", 409)

    resp = printer.getNozzleSize()
    resp = float(resp / 1000)

    return jsonify({"nozzle": resp})
Example #23
0
def printerPrintheadCommand():
    valid_commands = {"jog": [], "home": ["axes"], "feedrate": ["factor"]}
    command, data, response = get_json_command_from_request(
        request, valid_commands)
    if response is not None:
        return response

    if not printer.is_operational() or (printer.is_printing()
                                        and command != "feedrate"):
        # do not jog when a print job is running or we don't have a connection
        return make_response(
            "Printer is not operational or currently printing", 409)

    valid_axes = ["x", "y", "z"]
    ##~~ jog command
    if command == "jog":
        # validate all jog instructions, make sure that the values are numbers
        validated_values = {}
        for axis in valid_axes:
            if axis in data:
                value = data[axis]
                if not isinstance(value, (int, float)):
                    return make_response(
                        "Not a number for axis %s: %r" % (axis, value), 400)
                validated_values[axis] = value

        absolute = "absolute" in data and data[
            "absolute"] in valid_boolean_trues
        speed = data.get("speed", None)

        # execute the jog commands
        printer.jog(validated_values, relative=not absolute, speed=speed)

    ##~~ home command
    elif command == "home":
        validated_values = []
        axes = data["axes"]
        for axis in axes:
            if not axis in valid_axes:
                return make_response("Invalid axis: %s" % axis, 400)
            validated_values.append(axis)

        # execute the home command
        printer.home(validated_values)

    elif command == "feedrate":
        factor = data["factor"]
        if not isinstance(factor, (int, float)):
            return make_response("Not a number for feed rate: %r" % factor,
                                 400)
        try:
            printer.feed_rate(factor)
        except ValueError as e:
            return make_response("Invalid value for feed rate: %s" % str(e),
                                 400)

    return NO_CONTENT
Example #24
0
def controlJob():
    if not printer.is_operational():
        return make_response("Printer is not operational", 409)

    valid_commands = {"start": [], "restart": [], "pause": [], "cancel": []}

    command, data, response = get_json_command_from_request(
        request, valid_commands)
    if response is not None:
        return response

    activePrintjob = printer.is_printing() or printer.is_paused()

    tags = {"source:api", "api:job"}

    user = current_user.get_name()

    with Permissions.PRINT.require(403):
        if command == "start":
            if activePrintjob:
                return make_response(
                    "Printer already has an active print job, did you mean 'restart'?",
                    409)
            printer.start_print(tags=tags, user=user)
        elif command == "restart":
            if not printer.is_paused():
                return make_response(
                    "Printer does not have an active print job or is not paused",
                    409)
            printer.start_print(tags=tags, user=user)
        elif command == "pause":
            if not activePrintjob:
                return make_response(
                    "Printer is neither printing nor paused, 'pause' command cannot be performed",
                    409)
            action = data.get("action", "toggle")
            if action == "toggle":
                printer.toggle_pause_print(tags=tags, user=user)
            elif action == "pause":
                printer.pause_print(tags=tags, user=user)
            elif action == "resume":
                printer.resume_print(tags=tags, user=user)
            else:
                return make_response(
                    "Unknown action '{}', allowed values for action parameter are 'pause', 'resume' and 'toggle'"
                    .format(action), 400)

    # Safety first, everyone can cancel a print, but log who canceled the print
    # to prevent fraudulent use
    if command == "cancel":
        if not activePrintjob:
            return make_response(
                "Printer is neither printing nor paused, 'cancel' command cannot be performed",
                409)
        printer.cancel_print(tags=tags, user=user)
    return NO_CONTENT
Example #25
0
def printerPrintheadCommand():
	valid_commands = {
		"jog": [],
		"home": ["axes"],
		"feedrate": ["factor"]
	}
	command, data, response = get_json_command_from_request(request, valid_commands)
	if response is not None:
		return response

	if not printer.is_operational() or (printer.is_printing() and command != "feedrate"):
		# do not jog when a print job is running or we don't have a connection
		return make_response("Printer is not operational or currently printing", 409)

	tags = {"source:api", "api:printer.printhead"}

	valid_axes = ["x", "y", "z"]
	##~~ jog command
	if command == "jog":
		# validate all jog instructions, make sure that the values are numbers
		validated_values = {}
		for axis in valid_axes:
			if axis in data:
				value = data[axis]
				if not isinstance(value, (int, long, float)):
					return make_response("Not a number for axis %s: %r" % (axis, value), 400)
				validated_values[axis] = value

		absolute = "absolute" in data and data["absolute"] in valid_boolean_trues
		speed = data.get("speed", None)

		# execute the jog commands
		printer.jog(validated_values, relative=not absolute, speed=speed, tags=tags)

	##~~ home command
	elif command == "home":
		validated_values = []
		axes = data["axes"]
		for axis in axes:
			if not axis in valid_axes:
				return make_response("Invalid axis: %s" % axis, 400)
			validated_values.append(axis)

		# execute the home command
		printer.home(validated_values, tags=tags)

	elif command == "feedrate":
		factor = data["factor"]
		if not isinstance(factor, (int, long, float)):
			return make_response("Not a number for feed rate: %r" % factor, 400)
		try:
			printer.feed_rate(factor, tags=tags)
		except ValueError as e:
			return make_response("Invalid value for feed rate: %s" % str(e), 400)

	return NO_CONTENT
Example #26
0
def printerCommand():
    if not printer.is_operational():
        abort(409, description="Printer is not operational")

    if "application/json" not in request.headers["Content-Type"]:
        abort(400, description="Expected content type JSON")

    data = request.get_json()

    if data is None:
        abort(400, description="Malformed JSON body in request")

    if "command" in data and "commands" in data:
        abort(400, description="'command' and 'commands' are mutually exclusive")
    elif ("command" in data or "commands" in data) and "script" in data:
        abort(400, description="'command'/'commands' and 'script' are mutually exclusive")
    elif not ("command" in data or "commands" in data or "script" in data):
        abort(400, description="Need one of 'command', 'commands' or 'script'")

    parameters = {}
    if "parameters" in data:
        parameters = data["parameters"]

    tags = {"source:api", "api:printer.command"}

    if "command" in data or "commands" in data:
        if "command" in data:
            commands = [data["command"]]
        else:
            if not isinstance(data["commands"], (list, tuple)):
                abort(400, description="commands is invalid")
            commands = data["commands"]

        commandsToSend = []
        for command in commands:
            commandToSend = command
            if len(parameters) > 0:
                commandToSend = command % parameters
            commandsToSend.append(commandToSend)

        printer.commands(commandsToSend, tags=tags)

    elif "script" in data:
        script_name = data["script"]
        context = {"parameters": parameters}
        if "context" in data:
            context["context"] = data["context"]

        try:
            printer.script(script_name, context=context, tags=tags)
        except UnknownScript:
            abort(404, description="Unknown script")

    return NO_CONTENT
Example #27
0
def printerCommand():
	if not printer.is_operational():
		return make_response("Printer is not operational", 409)

	if not "application/json" in request.headers["Content-Type"]:
		return make_response("Expected content type JSON", 400)

	try:
		data = request.json
	except BadRequest:
		return make_response("Malformed JSON body in request", 400)

	if "command" in data and "commands" in data:
		return make_response("'command' and 'commands' are mutually exclusive", 400)
	elif ("command" in data or "commands" in data) and "script" in data:
		return make_response("'command'/'commands' and 'script' are mutually exclusive", 400)
	elif not ("command" in data or "commands" in data or "script" in data):
		return make_response("Need one of 'command', 'commands' or 'script'", 400)

	parameters = dict()
	if "parameters" in data:
		parameters = data["parameters"]

	tags = {"source:api", "api:printer.command"}

	if "command" in data or "commands" in data:
		if "command" in data:
			commands = [data["command"]]
		else:
			if not isinstance(data["commands"], (list, tuple)):
				return make_response("'commands' needs to be a list", 400)
			commands = data["commands"]

		commandsToSend = []
		for command in commands:
			commandToSend = command
			if len(parameters) > 0:
				commandToSend = command % parameters
			commandsToSend.append(commandToSend)

		printer.commands(commandsToSend, tags=tags)

	elif "script" in data:
		script_name = data["script"]
		context = dict(parameters=parameters)
		if "context" in data:
			context["context"] = data["context"]

		try:
			printer.script(script_name, context=context, tags=tags)
		except UnknownScript:
			return make_response("Unknown script: {script_name}".format(**locals()), 404)

	return NO_CONTENT
Example #28
0
def printerBedState():
    if not printer.is_operational():
        abort(409, description="Printer is not operational")

    if not printerProfileManager.get_current_or_default()["heatedBed"]:
        abort(409, description="Printer does not have a heated bed")

    data = _get_temperature_data(_keep_bed)
    if isinstance(data, Response):
        return data
    else:
        return jsonify(data)
Example #29
0
def printerBedState():
    if not printer.is_operational():
        return make_response("Printer is not operational", 409)

    if not printerProfileManager.get_current_or_default()["heatedBed"]:
        return make_response("Printer does not have a heated bed", 409)

    data = _get_temperature_data(_delete_tools)
    if isinstance(data, Response):
        return data
    else:
        return jsonify(data)
Example #30
0
def printerToolState():
	if not printer.is_operational():
		return make_response("Printer is not operational", 409)

	def deleteBed(x):
		data = dict(x)

		if "bed" in data.keys():
			del data["bed"]
		return data

	return jsonify(_getTemperatureData(deleteBed))
Example #31
0
def printerBedState():
	if not printer.is_operational():
		return make_response("Printer is not operational", 409)

	if not printerProfileManager.get_current_or_default()["heatedBed"]:
		return make_response("Printer does not have a heated bed", 409)

	data = _get_temperature_data(_delete_tools)
	if isinstance(data, Response):
		return data
	else:
		return jsonify(data)
Example #32
0
def printerChamberState():
	if not printer.is_operational():
		return make_response("Printer is not operational", 409)

	if not printerProfileManager.get_current_or_default()["heatedChamber"]:
		return make_response("Printer does not have a heated chamber", 409)

	data = _get_temperature_data(_keep_chamber)
	if isinstance(data, Response):
		return data
	else:
		return jsonify(data)
Example #33
0
def printerPrintheadCommand():
    valid_commands = {"jog": [], "home": ["axes"], "feedrate": ["factor"]}
    command, data, response = get_json_command_from_request(request, valid_commands)
    if response is not None:
        return response

    if not printer.is_operational() or (printer.is_printing() and command != "feedrate"):
        # do not jog when a print job is running or we don't have a connection
        abort(409, description="Printer is not operational or currently printing")

    tags = {"source:api", "api:printer.printhead"}

    valid_axes = ["x", "y", "z"]
    ##~~ jog command
    if command == "jog":
        # validate all jog instructions, make sure that the values are numbers
        validated_values = {}
        for axis in valid_axes:
            if axis in data:
                value = data[axis]
                if not isinstance(value, (int, long, float)):
                    abort(400, description="axis value is invalid")
                validated_values[axis] = value

        absolute = "absolute" in data and data["absolute"] in valid_boolean_trues
        speed = data.get("speed", None)

        # execute the jog commands
        printer.jog(validated_values, relative=not absolute, speed=speed, tags=tags)

    ##~~ home command
    elif command == "home":
        validated_values = []
        axes = data["axes"]
        for axis in axes:
            if axis not in valid_axes:
                abort(400, description="axis is invalid")
            validated_values.append(axis)

        # execute the home command
        printer.home(validated_values, tags=tags)

    elif command == "feedrate":
        factor = data["factor"]
        if not isinstance(factor, (int, long, float)):
            abort(400, description="factor is invalid")
        try:
            printer.feed_rate(factor, tags=tags)
        except ValueError:
            abort(400, description="factor is invalid")

    return NO_CONTENT
Example #34
0
def controlJob():
	if not printer.is_operational():
		return make_response("Printer is not operational", 409)

	valid_commands = {
		"start": [],
		"restart": [],
		"pause": [],
		"cancel": [],
		"shutdown": []
	}

	command, data, response = get_json_command_from_request(request, valid_commands)
	if response is not None:
		return response

	activePrintjob = printer.is_printing() or printer.is_paused() or printer.is_preparing_print() or printer.is_shutdown()

	if command == "start":
		if activePrintjob:
			return make_response("Printer already has an active print job, did you mean 'restart'?", 409)
		printer.start_print()
	elif command == "restart":
		if not printer.is_paused():
			return make_response("Printer does not have an active print job or is not paused", 409)
		printer.start_print()
	elif command == "pause":
		if not activePrintjob:
			return make_response("Printer is neither printing nor paused, 'pause' command cannot be performed", 409)
		action = data.get("action", "toggle")
		if action == "toggle":
			printer.toggle_pause_print()
		elif action == "pause":
			printer.pause_print()
		elif action == "resume":
			printer.resume_print()
		else:
			return make_response("Unknown action '{}', allowed values for action parameter are 'pause', 'resume' and 'toggle'".format(action), 400)
	elif command == "cancel":
		if not activePrintjob:
			printer.unselect_file()
		else:
			printer.cancel_print()
	elif command == "shutdown":
		if not printer.is_paused():
			return make_response("Printer does not have an active print job or is not paused", 409)
		printer.enter_shutdown_mode()

	return NO_CONTENT
Example #35
0
def controlJob():
    if not printer.is_operational():
        return make_response("Printer is not operational", 409)

    valid_commands = {"start": [], "restart": [], "pause": [], "cancel": []}

    command, data, response = get_json_command_from_request(
        request, valid_commands)
    if response is not None:
        return response

    activePrintjob = printer.is_printing() or printer.is_paused()

    if command == "start":
        if activePrintjob:
            return make_response(
                "Printer already has an active print job, did you mean 'restart'?",
                409)
        printer.start_print()
    elif command == "restart":
        if not printer.is_paused():
            return make_response(
                "Printer does not have an active print job or is not paused",
                409)
        printer.start_print()
    elif command == "pause":
        if not activePrintjob:
            return make_response(
                "Printer is neither printing nor paused, 'pause' command cannot be performed",
                409)
        action = data.get("action", "toggle")
        if action == "toggle":
            printer.toggle_pause_print()
        elif action == "pause":
            printer.pause_print()
        elif action == "resume":
            printer.resume_print()
        else:
            return make_response(
                "Unknown action '{}', allowed values for action parameter are 'pause', 'resume' and 'toggle'"
                .format(action), 400)
    elif command == "cancel":
        if not activePrintjob:
            return make_response(
                "Printer is neither printing nor paused, 'cancel' command cannot be performed",
                409)
        printer.cancel_print()
    return NO_CONTENT
Example #36
0
def printerBedState():
	if not printer.is_operational():
		return make_response("Printer is not operational", 409)

	def deleteTools(x):
		data = dict(x)

		for k in data.keys():
			if k.startswith("tool"):
				del data[k]
		return data

	data = _getTemperatureData(deleteTools)
	if isinstance(data, Response):
		return data
	else:
		return jsonify(data)
Example #37
0
def printerChamberCommand():
	if not printer.is_operational():
		return make_response("Printer is not operational", 409)

	if not printerProfileManager.get_current_or_default()["heatedChamber"]:
		return make_response("Printer does not have a heated chamber", 409)

	valid_commands = {
		"target": ["target"],
		"offset": ["offset"]
	}
	command, data, response = get_json_command_from_request(request, valid_commands)
	if response is not None:
		return response

	tags = {"source:api", "api:printer.chamber"}

	##~~ temperature
	if command == "target":
		target = data["target"]

		# make sure the target is a number
		if not isinstance(target, (int, long, float)):
			return make_response("Not a number: %r" % target, 400)

		# perform the actual temperature command
		printer.set_temperature("chamber", target, tags=tags)

	##~~ temperature offset
	elif command == "offset":
		offset = data["offset"]

		# make sure the offset is valid
		if not isinstance(offset, (int, long, float)):
			return make_response("Not a number: %r" % offset, 400)
		if not -50 <= offset <= 50:
			return make_response("Offset not in range [-50, 50]: %f" % offset, 400)

		# set the offsets
		printer.set_temperature_offset({"chamber": offset})

	return NO_CONTENT
Example #38
0
def _getTemperatureData(filter):
	if not printer.is_operational():
		return make_response("Printer is not operational", 409)

	tempData = printer.get_current_temperatures()

	if "history" in request.values.keys() and request.values["history"] in valid_boolean_trues:
		tempHistory = printer.get_temperature_history()

		limit = 300
		if "limit" in request.values.keys() and unicode(request.values["limit"]).isnumeric():
			limit = int(request.values["limit"])

		history = list(tempHistory)
		limit = min(limit, len(history))

		tempData.update({
			"history": map(lambda x: filter(x), history[-limit:])
		})

	return filter(tempData)
Example #39
0
def printerBedCommand():
	if not printer.is_operational():
		return make_response("Printer is not operational", 409)

	valid_commands = {
		"target": ["target"],
		"offset": ["offset"]
	}
	command, data, response = get_json_command_from_request(request, valid_commands)
	if response is not None:
		return response

	##~~ temperature
	if command == "target":
		target = data["target"]

		# make sure the target is a number
		if not isinstance(target, (int, long, float)):
			return make_response("Not a number: %r" % target, 400)

		# perform the actual temperature command
		printer.set_temperature("bed", target)

	##~~ temperature offset
	elif command == "offset":
		offset = data["offset"]

		# make sure the offset is valid
		if not isinstance(offset, (int, long, float)):
			return make_response("Not a number: %r" % offset, 400)
		if not -50 <= offset <= 50:
			return make_response("Offset not in range [-50, 50]: %f" % offset, 400)

		# set the offsets
		printer.set_temperature_offset({"bed": offset})

	return NO_CONTENT
Example #40
0
def printerState():
	if not printer.is_operational():
		return make_response("Printer is not operational", 409)

	# process excludes
	excludes = []
	if "exclude" in request.values:
		excludeStr = request.values["exclude"]
		if len(excludeStr.strip()) > 0:
			excludes = filter(lambda x: x in ["temperature", "sd", "state"], map(lambda x: x.strip(), excludeStr.split(",")))

	result = {}

	# add temperature information
	if not "temperature" in excludes:
		processor = lambda x: x
		heated_bed = printerProfileManager.get_current_or_default()["heatedBed"]
		heated_chamber = printerProfileManager.get_current_or_default()["heatedChamber"]
		if not heated_bed and not heated_chamber:
			processor = _keep_tools
		elif not heated_bed:
			processor = _delete_bed
		elif not heated_chamber:
			processor = _delete_chamber

		result.update({"temperature": _get_temperature_data(processor)})

	# add sd information
	if not "sd" in excludes and settings().getBoolean(["feature", "sdSupport"]):
		result.update({"sd": {"ready": printer.is_sd_ready()}})

	# add state information
	if not "state" in excludes:
		state = printer.get_current_data()["state"]
		result.update({"state": state})

	return jsonify(result)
Example #41
0
def printerToolCommand():
	if not printer.is_operational():
		return make_response("Printer is not operational", 409)

	valid_commands = {
		"select": ["tool"],
		"target": ["targets"],
		"offset": ["offsets"],
		"extrude": ["amount"],
		"flowrate": ["factor"]
	}
	command, data, response = get_json_command_from_request(request, valid_commands)
	if response is not None:
		return response

	validation_regex = re.compile("tool\d+")

	##~~ tool selection
	if command == "select":
		tool = data["tool"]
		if re.match(validation_regex, tool) is None:
			return make_response("Invalid tool: %s" % tool, 400)
		if not tool.startswith("tool"):
			return make_response("Invalid tool for selection: %s" % tool, 400)

		printer.change_tool(tool)

	##~~ temperature
	elif command == "target":
		targets = data["targets"]

		# make sure the targets are valid and the values are numbers
		validated_values = {}
		for tool, value in targets.iteritems():
			if re.match(validation_regex, tool) is None:
				return make_response("Invalid target for setting temperature: %s" % tool, 400)
			if not isinstance(value, (int, long, float)):
				return make_response("Not a number for %s: %r" % (tool, value), 400)
			validated_values[tool] = value

		# perform the actual temperature commands
		for tool in validated_values.keys():
			printer.set_temperature(tool, validated_values[tool])

	##~~ temperature offset
	elif command == "offset":
		offsets = data["offsets"]

		# make sure the targets are valid, the values are numbers and in the range [-50, 50]
		validated_values = {}
		for tool, value in offsets.iteritems():
			if re.match(validation_regex, tool) is None:
				return make_response("Invalid target for setting temperature: %s" % tool, 400)
			if not isinstance(value, (int, long, float)):
				return make_response("Not a number for %s: %r" % (tool, value), 400)
			if not -50 <= value <= 50:
				return make_response("Offset %s not in range [-50, 50]: %f" % (tool, value), 400)
			validated_values[tool] = value

		# set the offsets
		printer.set_temperature_offset(validated_values)

	##~~ extrusion
	elif command == "extrude":
		if printer.is_printing():
			# do not extrude when a print job is running
			return make_response("Printer is currently printing", 409)

		amount = data["amount"]
		if not isinstance(amount, (int, long, float)):
			return make_response("Not a number for extrusion amount: %r" % amount, 400)
		printer.extrude(amount)

	elif command == "flowrate":
		factor = data["factor"]
		if not isinstance(factor, (int, long, float)):
			return make_response("Not a number for flow rate: %r" % factor, 400)
		try:
			printer.flow_rate(factor)
		except ValueError as e:
			return make_response("Invalid value for flow rate: %s" % str(e), 400)

	return NO_CONTENT
Example #42
0
def gcodeFileCommand(filename, target):
	if not target in [FileDestinations.LOCAL, FileDestinations.SDCARD]:
		return make_response("Unknown target: %s" % target, 404)

	if not _verifyFileExists(target, filename):
		return make_response("File not found on '%s': %s" % (target, filename), 404)

	# valid file commands, dict mapping command name to mandatory parameters
	valid_commands = {
		"select": [],
		"slice": []
	}

	command, data, response = get_json_command_from_request(request, valid_commands)
	if response is not None:
		return response

	if command == "select":
		# selects/loads a file
		printAfterLoading = False
		if "print" in data.keys() and data["print"] in valid_boolean_trues:
			if not printer.is_operational():
				return make_response("Printer is not operational, cannot directly start printing", 409)
			printAfterLoading = True

		sd = False
		if target == FileDestinations.SDCARD:
			filenameToSelect = filename
			sd = True
		else:
			filenameToSelect = fileManager.path_on_disk(target, filename)
		printer.select_file(filenameToSelect, sd, printAfterLoading)

	elif command == "slice":
		try:
			if "slicer" in data:
				slicer = data["slicer"]
				del data["slicer"]
				slicer_instance = slicingManager.get_slicer(slicer)

			elif "cura" in slicingManager.registered_slicers:
				slicer = "cura"
				slicer_instance = slicingManager.get_slicer("cura")

			else:
				return make_response("Cannot slice {filename}, no slicer available".format(**locals()), 415)
		except octoprint.slicing.UnknownSlicer as e:
			return make_response("Slicer {slicer} is not available".format(slicer=e.slicer), 400)

		if not any([octoprint.filemanager.valid_file_type(filename, type=source_file_type) for source_file_type in slicer_instance.get_slicer_properties().get("source_file_types", ["model"])]):
			return make_response("Cannot slice {filename}, not a model file".format(**locals()), 415)

		if slicer_instance.get_slicer_properties().get("same_device", True) and (printer.is_printing() or printer.is_paused()):
			# slicer runs on same device as OctoPrint, slicing while printing is hence disabled
			return make_response("Cannot slice on {slicer} while printing due to performance reasons".format(**locals()), 409)

		if "destination" in data and data["destination"]:
			destination = data["destination"]
			del data["destination"]
		elif "gcode" in data and data["gcode"]:
			destination = data["gcode"]
			del data["gcode"]
		else:
			import os
			name, _ = os.path.splitext(filename)
			destination = name + "." + slicer_instance.get_slicer_properties().get("destination_extensions", ["gco", "gcode", "g"])[0]

		# prohibit overwriting the file that is currently being printed
		currentOrigin, currentFilename = _getCurrentFile()
		if currentFilename == destination and currentOrigin == target and (printer.is_printing() or printer.is_paused()):
			make_response("Trying to slice into file that is currently being printed: %s" % destination, 409)

		if "profile" in data.keys() and data["profile"]:
			profile = data["profile"]
			del data["profile"]
		else:
			profile = None

		if "printerProfile" in data.keys() and data["printerProfile"]:
			printerProfile = data["printerProfile"]
			del data["printerProfile"]
		else:
			printerProfile = None

		if "position" in data.keys() and data["position"] and isinstance(data["position"], dict) and "x" in data["position"] and "y" in data["position"]:
			position = data["position"]
			del data["position"]
		else:
			position = None

		select_after_slicing = False
		if "select" in data.keys() and data["select"] in valid_boolean_trues:
			if not printer.is_operational():
				return make_response("Printer is not operational, cannot directly select for printing", 409)
			select_after_slicing = True

		print_after_slicing = False
		if "print" in data.keys() and data["print"] in valid_boolean_trues:
			if not printer.is_operational():
				return make_response("Printer is not operational, cannot directly start printing", 409)
			select_after_slicing = print_after_slicing = True

		override_keys = [k for k in data if k.startswith("profile.") and data[k] is not None]
		overrides = dict()
		for key in override_keys:
			overrides[key[len("profile."):]] = data[key]

		def slicing_done(target, gcode_name, select_after_slicing, print_after_slicing):
			if select_after_slicing or print_after_slicing:
				sd = False
				if target == FileDestinations.SDCARD:
					filenameToSelect = gcode_name
					sd = True
				else:
					filenameToSelect = fileManager.path_on_disk(target, gcode_name)
				printer.select_file(filenameToSelect, sd, print_after_slicing)

		try:
			fileManager.slice(slicer, target, filename, target, destination,
			                  profile=profile,
			                  printer_profile_id=printerProfile,
			                  position=position,
			                  overrides=overrides,
			                  callback=slicing_done,
			                  callback_args=(target, destination, select_after_slicing, print_after_slicing))
		except octoprint.slicing.UnknownProfile:
			return make_response("Profile {profile} doesn't exist".format(**locals()), 400)

		files = {}
		location = url_for(".readGcodeFile", target=target, filename=destination, _external=True)
		result = {
			"name": destination,
			"origin": FileDestinations.LOCAL,
			"refs": {
				"resource": location,
				"download": url_for("index", _external=True) + "downloads/files/" + target + "/" + destination
			}
		}

		r = make_response(jsonify(result), 202)
		r.headers["Location"] = location
		return r

	return NO_CONTENT
Example #43
0
def uploadGcodeFile(target):
	input_name = "file"
	input_upload_name = input_name + "." + settings().get(["server", "uploads", "nameSuffix"])
	input_upload_path = input_name + "." + settings().get(["server", "uploads", "pathSuffix"])
	if input_upload_name in request.values and input_upload_path in request.values:
		if not target in [FileDestinations.LOCAL, FileDestinations.SDCARD]:
			return make_response("Unknown target: %s" % target, 404)

		upload = octoprint.filemanager.util.DiskFileWrapper(request.values[input_upload_name], request.values[input_upload_path])

		# Store any additional user data the caller may have passed.
		userdata = None
		if "userdata" in request.values:
			import json
			try:
				userdata = json.loads(request.values["userdata"])
			except:
				return make_response("userdata contains invalid JSON", 400)

		if target == FileDestinations.SDCARD and not settings().getBoolean(["feature", "sdSupport"]):
			return make_response("SD card support is disabled", 404)

		sd = target == FileDestinations.SDCARD
		selectAfterUpload = "select" in request.values.keys() and request.values["select"] in valid_boolean_trues
		printAfterSelect = "print" in request.values.keys() and request.values["print"] in valid_boolean_trues

		if sd:
			# validate that all preconditions for SD upload are met before attempting it
			if not (printer.is_operational() and not (printer.is_printing() or printer.is_paused())):
				return make_response("Can not upload to SD card, printer is either not operational or already busy", 409)
			if not printer.is_sd_ready():
				return make_response("Can not upload to SD card, not yet initialized", 409)

		# determine future filename of file to be uploaded, abort if it can't be uploaded
		try:
			# FileDestinations.LOCAL = should normally be target, but can't because SDCard handling isn't implemented yet
			futurePath, futureFilename = fileManager.sanitize(FileDestinations.LOCAL, upload.filename)
		except:
			futurePath = None
			futureFilename = None

		if futureFilename is None:
			return make_response("Can not upload file %s, wrong format?" % upload.filename, 415)

		if "path" in request.values and request.values["path"]:
			# we currently only support uploads to sdcard via local, so first target is local instead of "target"
			futurePath = fileManager.sanitize_path(FileDestinations.LOCAL, request.values["path"])

		# prohibit overwriting currently selected file while it's being printed
		futureFullPath = fileManager.join_path(FileDestinations.LOCAL, futurePath, futureFilename)
		futureFullPathInStorage = fileManager.path_in_storage(FileDestinations.LOCAL, futureFullPath)

		if not printer.can_modify_file(futureFullPathInStorage, sd):
			return make_response("Trying to overwrite file that is currently being printed: %s" % futureFullPath, 409)

		reselect = printer.is_current_file(futureFullPathInStorage, sd)

		def fileProcessingFinished(filename, absFilename, destination):
			"""
			Callback for when the file processing (upload, optional slicing, addition to analysis queue) has
			finished.

			Depending on the file's destination triggers either streaming to SD card or directly calls selectAndOrPrint.
			"""

			if destination == FileDestinations.SDCARD and octoprint.filemanager.valid_file_type(filename, "gcode"):
				return filename, printer.add_sd_file(filename, absFilename, selectAndOrPrint)
			else:
				selectAndOrPrint(filename, absFilename, destination)
				return filename

		def selectAndOrPrint(filename, absFilename, destination):
			"""
			Callback for when the file is ready to be selected and optionally printed. For SD file uploads this is only
			the case after they have finished streaming to the printer, which is why this callback is also used
			for the corresponding call to addSdFile.

			Selects the just uploaded file if either selectAfterUpload or printAfterSelect are True, or if the
			exact file is already selected, such reloading it.
			"""
			if octoprint.filemanager.valid_file_type(added_file, "gcode") and (selectAfterUpload or printAfterSelect or reselect):
				printer.select_file(absFilename, destination == FileDestinations.SDCARD, printAfterSelect)

		try:
			added_file = fileManager.add_file(FileDestinations.LOCAL, futureFullPathInStorage, upload, allow_overwrite=True)
		except octoprint.filemanager.storage.StorageError as e:
			if e.code == octoprint.filemanager.storage.StorageError.INVALID_FILE:
				return make_response("Could not upload the file \"{}\", invalid type".format(upload.filename), 400)
			else:
				return make_response("Could not upload the file \"{}\"".format(upload.filename), 500)

		if octoprint.filemanager.valid_file_type(added_file, "stl"):
			filename = added_file
			done = True
		else:
			filename = fileProcessingFinished(added_file, fileManager.path_on_disk(FileDestinations.LOCAL, added_file), target)
			done = not sd

		if userdata is not None:
			# upload included userdata, add this now to the metadata
			fileManager.set_additional_metadata(FileDestinations.LOCAL, added_file, "userdata", userdata)

		sdFilename = None
		if isinstance(filename, tuple):
			filename, sdFilename = filename

		eventManager.fire(Events.UPLOAD, {"name": futureFilename,
		                                  "path": filename,
		                                  "target": target,

		                                  # TODO deprecated, remove in 1.4.0
		                                  "file": filename})

		files = {}
		location = url_for(".readGcodeFile", target=FileDestinations.LOCAL, filename=filename, _external=True)
		files.update({
			FileDestinations.LOCAL: {
				"name": futureFilename,
				"path": filename,
				"origin": FileDestinations.LOCAL,
				"refs": {
					"resource": location,
					"download": url_for("index", _external=True) + "downloads/files/" + FileDestinations.LOCAL + "/" + filename
				}
			}
		})

		if sd and sdFilename:
			location = url_for(".readGcodeFile", target=FileDestinations.SDCARD, filename=sdFilename, _external=True)
			files.update({
				FileDestinations.SDCARD: {
					"name": sdFilename,
					"path": sdFilename,
					"origin": FileDestinations.SDCARD,
					"refs": {
						"resource": location
					}
				}
			})

		r = make_response(jsonify(files=files, done=done), 201)
		r.headers["Location"] = location
		return r

	elif "foldername" in request.values:
		foldername = request.values["foldername"]

		if not target in [FileDestinations.LOCAL]:
			return make_response("Unknown target: %s" % target, 400)

		futurePath, futureName = fileManager.sanitize(target, foldername)
		if not futureName or not futurePath:
			return make_response("Can't create a folder with an empty name", 400)

		if "path" in request.values and request.values["path"]:
			futurePath = fileManager.sanitize_path(FileDestinations.LOCAL,
			                                       request.values["path"])

		futureFullPath = fileManager.join_path(target, futurePath, futureName)
		if octoprint.filemanager.valid_file_type(futureName):
			return make_response("Can't create a folder named %s, please try another name" % futureName, 409)

		try:
			added_folder = fileManager.add_folder(target, futureFullPath)
		except octoprint.filemanager.storage.StorageError as e:
			if e.code == octoprint.filemanager.storage.StorageError.INVALID_DIRECTORY:
				return make_response("Could not create folder {}, invalid directory".format(futureName))
			else:
				return make_response("Could not create folder {}".format(futureName))

		location = url_for(".readGcodeFile",
		                   target=FileDestinations.LOCAL,
		                   filename=added_folder,
		                   _external=True)
		folder = dict(name=futureName,
		              path=added_folder,
		              origin=target,
		              refs=dict(resource=location))

		r = make_response(jsonify(folder=folder, done=True), 201)
		r.headers["Location"] = location
		return r

	else:
		return make_response("No file to upload and no folder to create", 400)
Example #44
0
def printerToolState():
	if not printer.is_operational():
		return make_response("Printer is not operational", 409)

	return jsonify(_get_temperature_data(_keep_tools))
Example #45
0
def gcodeFileCommand(filename, target):
	if not target in [FileDestinations.LOCAL, FileDestinations.SDCARD]:
		return make_response("Unknown target: %s" % target, 404)

	# valid file commands, dict mapping command name to mandatory parameters
	valid_commands = {
		"select": [],
		"slice": [],
		"copy": ["destination"],
		"move": ["destination"]
	}

	command, data, response = get_json_command_from_request(request, valid_commands)
	if response is not None:
		return response

	if command == "select":
		if not _verifyFileExists(target, filename):
			return make_response("File not found on '%s': %s" % (target, filename), 404)

		# selects/loads a file
		if not octoprint.filemanager.valid_file_type(filename, type="machinecode"):
			return make_response("Cannot select {filename} for printing, not a machinecode file".format(**locals()), 415)

		printAfterLoading = False
		if "print" in data.keys() and data["print"] in valid_boolean_trues:
			if not printer.is_operational():
				return make_response("Printer is not operational, cannot directly start printing", 409)
			printAfterLoading = True

		sd = False
		if target == FileDestinations.SDCARD:
			filenameToSelect = filename
			sd = True
		else:
			filenameToSelect = fileManager.path_on_disk(target, filename)
		printer.select_file(filenameToSelect, sd, printAfterLoading)

	elif command == "slice":
		if not _verifyFileExists(target, filename):
			return make_response("File not found on '%s': %s" % (target, filename), 404)

		try:
			if "slicer" in data:
				slicer = data["slicer"]
				del data["slicer"]
				slicer_instance = slicingManager.get_slicer(slicer)

			elif "cura" in slicingManager.registered_slicers:
				slicer = "cura"
				slicer_instance = slicingManager.get_slicer("cura")

			else:
				return make_response("Cannot slice {filename}, no slicer available".format(**locals()), 415)
		except octoprint.slicing.UnknownSlicer as e:
			return make_response("Slicer {slicer} is not available".format(slicer=e.slicer), 400)

		if not any([octoprint.filemanager.valid_file_type(filename, type=source_file_type) for source_file_type in slicer_instance.get_slicer_properties().get("source_file_types", ["model"])]):
			return make_response("Cannot slice {filename}, not a model file".format(**locals()), 415)

		if slicer_instance.get_slicer_properties().get("same_device", True) and (printer.is_printing() or printer.is_paused()):
			# slicer runs on same device as OctoPrint, slicing while printing is hence disabled
			return make_response("Cannot slice on {slicer} while printing due to performance reasons".format(**locals()), 409)

		if "destination" in data and data["destination"]:
			destination = data["destination"]
			del data["destination"]
		elif "gcode" in data and data["gcode"]:
			destination = data["gcode"]
			del data["gcode"]
		else:
			import os
			name, _ = os.path.splitext(filename)
			destination = name + "." + slicer_instance.get_slicer_properties().get("destination_extensions", ["gco", "gcode", "g"])[0]

		full_path = destination
		if "path" in data and data["path"]:
			full_path = fileManager.join_path(target, data["path"], destination)
		else:
			path, _ = fileManager.split_path(target, filename)
			if path:
				full_path = fileManager.join_path(target, path, destination)

		# prohibit overwriting the file that is currently being printed
		currentOrigin, currentFilename = _getCurrentFile()
		if currentFilename == full_path and currentOrigin == target and (printer.is_printing() or printer.is_paused()):
			make_response("Trying to slice into file that is currently being printed: %s" % full_path, 409)

		if "profile" in data.keys() and data["profile"]:
			profile = data["profile"]
			del data["profile"]
		else:
			profile = None

		if "printerProfile" in data.keys() and data["printerProfile"]:
			printerProfile = data["printerProfile"]
			del data["printerProfile"]
		else:
			printerProfile = None

		if "position" in data.keys() and data["position"] and isinstance(data["position"], dict) and "x" in data["position"] and "y" in data["position"]:
			position = data["position"]
			del data["position"]
		else:
			position = None

		select_after_slicing = False
		if "select" in data.keys() and data["select"] in valid_boolean_trues:
			if not printer.is_operational():
				return make_response("Printer is not operational, cannot directly select for printing", 409)
			select_after_slicing = True

		print_after_slicing = False
		if "print" in data.keys() and data["print"] in valid_boolean_trues:
			if not printer.is_operational():
				return make_response("Printer is not operational, cannot directly start printing", 409)
			select_after_slicing = print_after_slicing = True

		override_keys = [k for k in data if k.startswith("profile.") and data[k] is not None]
		overrides = dict()
		for key in override_keys:
			overrides[key[len("profile."):]] = data[key]

		def slicing_done(target, path, select_after_slicing, print_after_slicing):
			if select_after_slicing or print_after_slicing:
				sd = False
				if target == FileDestinations.SDCARD:
					filenameToSelect = path
					sd = True
				else:
					filenameToSelect = fileManager.path_on_disk(target, path)
				printer.select_file(filenameToSelect, sd, print_after_slicing)

		try:
			fileManager.slice(slicer, target, filename, target, full_path,
			                  profile=profile,
			                  printer_profile_id=printerProfile,
			                  position=position,
			                  overrides=overrides,
			                  callback=slicing_done,
			                  callback_args=(target, full_path, select_after_slicing, print_after_slicing))
		except octoprint.slicing.UnknownProfile:
			return make_response("Profile {profile} doesn't exist".format(**locals()), 400)

		files = {}
		location = url_for(".readGcodeFile", target=target, filename=full_path, _external=True)
		result = {
			"name": destination,
			"path": full_path,
			"origin": FileDestinations.LOCAL,
			"refs": {
				"resource": location,
				"download": url_for("index", _external=True) + "downloads/files/" + target + "/" + full_path
			}
		}

		r = make_response(jsonify(result), 202)
		r.headers["Location"] = location
		return r

	elif command == "copy" or command == "move":
		# Copy and move are only possible on local storage
		if not target in [FileDestinations.LOCAL]:
			return make_response("Unsupported target for {}: {}".format(command, target), 400)

		if not _verifyFileExists(target, filename) and not _verifyFolderExists(target, filename):
			return make_response("File or folder not found on {}: {}".format(target, filename), 404)

		path, name = fileManager.split_path(target, filename)
		destination = data["destination"]
		if _verifyFolderExists(target, destination):
			# destination is an existing folder, we'll assume we are supposed to move filename to this
			# folder under the same name
			destination = fileManager.join_path(target, destination, name)

		if _verifyFileExists(target, destination) or _verifyFolderExists(target, destination):
			return make_response("File or folder does already exist on {}: {}".format(target, destination), 409)

		is_file = fileManager.file_exists(target, filename)
		is_folder = fileManager.folder_exists(target, filename)

		if not (is_file or is_folder):
			return make_response("{} on {} is neither file or folder, can't {}".format(filename, target, command), 400)

		if command == "copy":
			if is_file:
				fileManager.copy_file(target, filename, destination)
			else:
				fileManager.copy_folder(target, filename, destination)
		elif command == "move":
			if _isBusy(target, filename):
				return make_response("Trying to move a file or folder that is currently in use: {}".format(filename), 409)

			# deselect the file if it's currently selected
			currentOrigin, currentFilename = _getCurrentFile()
			if currentFilename is not None and filename == currentFilename:
				printer.unselect_file()

			if is_file:
				fileManager.move_file(target, filename, destination)
			else:
				fileManager.move_folder(target, filename, destination)

		location = url_for(".readGcodeFile", target=target, filename=destination, _external=True)
		result = {
			"name": name,
			"path": destination,
			"origin": FileDestinations.LOCAL,
			"refs": {
				"resource": location
			}
		}
		if is_file:
			result["refs"]["download"] = url_for("index", _external=True) + "downloads/files/" + target + "/" + destination

		r = make_response(jsonify(result), 201)
		r.headers["Location"] = location
		return r

	return NO_CONTENT
Example #46
0
def uploadGcodeFile(target):
	if not target in [FileDestinations.LOCAL, FileDestinations.SDCARD]:
		return make_response("Unknown target: %s" % target, 404)

	input_name = "file"
	input_upload_name = input_name + "." + settings().get(["server", "uploads", "nameSuffix"])
	input_upload_path = input_name + "." + settings().get(["server", "uploads", "pathSuffix"])
	if input_upload_name in request.values and input_upload_path in request.values:
		upload = octoprint.filemanager.util.DiskFileWrapper(request.values[input_upload_name], request.values[input_upload_path])
	else:
		return make_response("No file included", 400)

	# Store any additional user data the caller may have passed.
	userdata = None
	if "userdata" in request.values:
		import json
		try:
			userdata = json.loads(request.values["userdata"])
		except:
			return make_response("userdata contains invalid JSON", 400)

	if target == FileDestinations.SDCARD and not settings().getBoolean(["feature", "sdSupport"]):
		return make_response("SD card support is disabled", 404)

	sd = target == FileDestinations.SDCARD
	selectAfterUpload = "select" in request.values.keys() and request.values["select"] in valid_boolean_trues
	printAfterSelect = "print" in request.values.keys() and request.values["print"] in valid_boolean_trues

	if sd:
		# validate that all preconditions for SD upload are met before attempting it
		if not (printer.is_operational() and not (printer.is_printing() or printer.is_paused())):
			return make_response("Can not upload to SD card, printer is either not operational or already busy", 409)
		if not printer.is_sd_ready():
			return make_response("Can not upload to SD card, not yet initialized", 409)

	# determine current job
	currentFilename = None
	currentOrigin = None
	currentJob = printer.get_current_job()
	if currentJob is not None and "file" in currentJob.keys():
		currentJobFile = currentJob["file"]
		if "name" in currentJobFile.keys() and "origin" in currentJobFile.keys():
			currentFilename = currentJobFile["name"]
			currentOrigin = currentJobFile["origin"]

	# determine future filename of file to be uploaded, abort if it can't be uploaded
	try:
		futureFilename = fileManager.sanitize_name(FileDestinations.LOCAL, upload.filename)
	except:
		futureFilename = None
	if futureFilename is None:
		return make_response("Can not upload file %s, wrong format?" % upload.filename, 415)

	# prohibit overwriting currently selected file while it's being printed
	if futureFilename == currentFilename and target == currentOrigin and printer.is_printing() or printer.is_paused():
		return make_response("Trying to overwrite file that is currently being printed: %s" % currentFilename, 409)

	def fileProcessingFinished(filename, absFilename, destination):
		"""
		Callback for when the file processing (upload, optional slicing, addition to analysis queue) has
		finished.

		Depending on the file's destination triggers either streaming to SD card or directly calls selectAndOrPrint.
		"""

		if destination == FileDestinations.SDCARD and octoprint.filemanager.valid_file_type(filename, "gcode"):
			return filename, printer.add_sd_file(filename, absFilename, selectAndOrPrint)
		else:
			selectAndOrPrint(filename, absFilename, destination)
			return filename

	def selectAndOrPrint(filename, absFilename, destination):
		"""
		Callback for when the file is ready to be selected and optionally printed. For SD file uploads this is only
		the case after they have finished streaming to the printer, which is why this callback is also used
		for the corresponding call to addSdFile.

		Selects the just uploaded file if either selectAfterUpload or printAfterSelect are True, or if the
		exact file is already selected, such reloading it.
		"""
		if octoprint.filemanager.valid_file_type(added_file, "gcode") and (selectAfterUpload or printAfterSelect or (currentFilename == filename and currentOrigin == destination)):
			printer.select_file(absFilename, destination == FileDestinations.SDCARD, printAfterSelect)

	added_file = fileManager.add_file(FileDestinations.LOCAL, upload.filename, upload, allow_overwrite=True)
	if added_file is None:
		return make_response("Could not upload the file %s" % upload.filename, 500)
	if octoprint.filemanager.valid_file_type(added_file, "stl"):
		filename = added_file
		done = True
	else:
		filename = fileProcessingFinished(added_file, fileManager.path_on_disk(FileDestinations.LOCAL, added_file), target)
		done = not sd

	if userdata is not None:
		# upload included userdata, add this now to the metadata
		fileManager.set_additional_metadata(FileDestinations.LOCAL, added_file, "userdata", userdata)

	sdFilename = None
	if isinstance(filename, tuple):
		filename, sdFilename = filename

	eventManager.fire(Events.UPLOAD, {"file": filename, "target": target})

	files = {}
	location = url_for(".readGcodeFile", target=FileDestinations.LOCAL, filename=filename, _external=True)
	files.update({
		FileDestinations.LOCAL: {
			"name": filename,
			"origin": FileDestinations.LOCAL,
			"refs": {
				"resource": location,
				"download": url_for("index", _external=True) + "downloads/files/" + FileDestinations.LOCAL + "/" + filename
			}
		}
	})

	if sd and sdFilename:
		location = url_for(".readGcodeFile", target=FileDestinations.SDCARD, filename=sdFilename, _external=True)
		files.update({
			FileDestinations.SDCARD: {
				"name": sdFilename,
				"origin": FileDestinations.SDCARD,
				"refs": {
					"resource": location
				}
			}
		})

	r = make_response(jsonify(files=files, done=done), 201)
	r.headers["Location"] = location
	return r