Added triggering GCODE scripts to the REST API and custom controls
This commit is contained in:
parent
e79fd99a41
commit
aecc7a4734
8 changed files with 97 additions and 26 deletions
|
|
@ -1,8 +1,8 @@
|
|||
.. _sec-api:
|
||||
|
||||
###
|
||||
API
|
||||
###
|
||||
########
|
||||
REST API
|
||||
########
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
|
|
|||
|
|
@ -953,8 +953,20 @@ Arbitrary Command Request
|
|||
* - ``command``
|
||||
- 0..1
|
||||
- String
|
||||
- Single command to send to the printer, mutually exclusive with ``commands``.
|
||||
- Single command to send to the printer, mutually exclusive with ``commands`` and ``script``.
|
||||
* - ``commands``
|
||||
- 0..*
|
||||
- Array of String
|
||||
- Multiple commands to send to the printer (in the given order), mutually exclusive with ``command``.
|
||||
- Multiple commands to send to the printer (in the given order), mutually exclusive with ``command`` and ``script``.
|
||||
* - ``script``
|
||||
- 0..*
|
||||
- String
|
||||
- Name of the GCODE script template to send to the printer, mutually exclusive with ``command`` and ``commands``.
|
||||
* - ``parameters``
|
||||
- 0..1
|
||||
- Map of key value pairs
|
||||
- Key value pairs of parameters to replace in sent commands/provide to the script renderer
|
||||
* - ``context``
|
||||
- 0..1
|
||||
- Map of key value pairs
|
||||
- (only if ``script`` is set) additional template variables to provide to the script renderer
|
||||
|
|
|
|||
|
|
@ -104,6 +104,24 @@ class PrinterInterface(object):
|
|||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def script(self, name, context=None):
|
||||
"""
|
||||
Sends the GCODE script ``name`` to the printer.
|
||||
|
||||
The script will be run through the template engine, the rendering context can be extended by providing a
|
||||
``context`` with additional template variables to use.
|
||||
|
||||
If the script is unknown, an :class:`UnknownScriptException` will be raised.
|
||||
|
||||
Arguments:
|
||||
name (string): The name of the GCODE script to render.
|
||||
context (dict): An optional context of additional template variables to provide to the renderer.
|
||||
|
||||
Raises:
|
||||
UnknownScriptException: There is no GCODE script with name ``name``
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def jog(self, axis, amount):
|
||||
"""
|
||||
Jogs the specified printer ``axis`` by the specified ``amount`` in mm.
|
||||
|
|
@ -438,4 +456,6 @@ class PrinterCallback(object):
|
|||
"""
|
||||
pass
|
||||
|
||||
|
||||
class UnknownScript(BaseException):
|
||||
def __init__(self, name, *args, **kwargs):
|
||||
self.name = name
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ from octoprint import util as util
|
|||
from octoprint.events import eventManager, Events
|
||||
from octoprint.filemanager import FileDestinations
|
||||
from octoprint.plugin import plugin_manager, ProgressPlugin
|
||||
from octoprint.printer import PrinterInterface, PrinterCallback
|
||||
from octoprint.printer import PrinterInterface, PrinterCallback, UnknownScript
|
||||
from octoprint.printer.estimation import TimeEstimationHelper
|
||||
from octoprint.settings import settings
|
||||
from octoprint.util import comm as comm
|
||||
|
|
@ -230,6 +230,17 @@ class Printer(PrinterInterface, comm.MachineComPrintCallback):
|
|||
for command in commands:
|
||||
self._comm.sendCommand(command)
|
||||
|
||||
def script(self, name, context=None):
|
||||
if self._comm is None:
|
||||
return
|
||||
|
||||
if name is None or not name:
|
||||
raise ValueError("name must be set")
|
||||
|
||||
result = self._comm.sendGcodeScript(name, replacements=context)
|
||||
if not result:
|
||||
raise UnknownScript(name)
|
||||
|
||||
def jog(self, axis, amount):
|
||||
if not isinstance(axis, (str, unicode)):
|
||||
raise ValueError("axis must be a string: {axis}".format(axis=axis))
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ from octoprint.server.api import api
|
|||
from octoprint.server.util.flask import restricted_access, get_json_command_from_request
|
||||
import octoprint.util as util
|
||||
|
||||
from octoprint.printer import UnknownScript
|
||||
|
||||
#~~ Printer
|
||||
|
||||
|
||||
|
|
@ -332,30 +334,47 @@ def printerCommand():
|
|||
except JSONBadRequest:
|
||||
return make_response("Malformed JSON body in request", 400)
|
||||
|
||||
parameters = dict()
|
||||
if "parameters" in data.keys(): parameters = data["parameters"]
|
||||
|
||||
if "command" in data and "commands" in data:
|
||||
return make_response("'command' and 'commands' are mutually exclusive", 400)
|
||||
elif "command" in data:
|
||||
commands = [data["command"]]
|
||||
elif "commands" in data and isinstance(data["commands"], (list, tuple)):
|
||||
commands = data["commands"]
|
||||
else:
|
||||
return make_response("Need either single 'command' or list of 'commands'", 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)
|
||||
|
||||
commandsToSend = []
|
||||
for command in commands:
|
||||
commandToSend = command
|
||||
if len(parameters) > 0:
|
||||
commandToSend = command % parameters
|
||||
commandsToSend.append(commandToSend)
|
||||
parameters = dict()
|
||||
if "parameters" in data:
|
||||
parameters = data["parameters"]
|
||||
|
||||
printer.commands(commandsToSend)
|
||||
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)
|
||||
|
||||
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)
|
||||
except UnknownScript:
|
||||
return make_response("Unknown script: {script_name}".format(**locals()), 404)
|
||||
|
||||
return NO_CONTENT
|
||||
|
||||
|
||||
@api.route("/printer/command/custom", methods=["GET"])
|
||||
def getCustomControls():
|
||||
# TODO: document me
|
||||
|
|
|
|||
|
|
@ -810,6 +810,7 @@ class Settings(object):
|
|||
def loadScript(self, script_type, name, context=None, source=False):
|
||||
if context is None:
|
||||
context = dict()
|
||||
context.update(dict(script=dict(type=script_type, name=name)))
|
||||
|
||||
template = self._get_script_template(script_type, name, source=source)
|
||||
if template is None:
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ $(function() {
|
|||
};
|
||||
|
||||
self._processControl = function (control) {
|
||||
if (control.type == "parametric_command" || control.type == "parametric_commands") {
|
||||
if (_.startsWith(control.type, "parametric_")) {
|
||||
for (var i = 0; i < control.input.length; i++) {
|
||||
control.input[i].value = ko.observable(control.input[i].default);
|
||||
if (!control.input[i].hasOwnProperty("slider")) {
|
||||
|
|
@ -281,9 +281,14 @@ $(function() {
|
|||
} else if (command.type == "commands" || command.type == "parametric_commands") {
|
||||
// multi command
|
||||
data = {"commands": command.commands};
|
||||
} else if (command.type == "script" || command.type == "parametric_script") {
|
||||
data = {"script": command.script};
|
||||
if (command.hasOwnProperty("context")) {
|
||||
data["context"] = command.context;
|
||||
}
|
||||
}
|
||||
|
||||
if (command.type == "parametric_command" || command.type == "parametric_commands") {
|
||||
if (command.type == "parametric_command" || command.type == "parametric_commands" || command.type == "parametric_script") {
|
||||
// parametric command(s)
|
||||
data["parameters"] = {};
|
||||
for (var i = 0; i < command.input.length; i++) {
|
||||
|
|
@ -319,9 +324,11 @@ $(function() {
|
|||
return "customControls_sectionRowTemplate";
|
||||
case "command":
|
||||
case "commands":
|
||||
case "script":
|
||||
return "customControls_commandTemplate";
|
||||
case "parametric_command":
|
||||
case "parametric_commands":
|
||||
case "parametric_script":
|
||||
return "customControls_parametricCommandTemplate";
|
||||
case "feedback_command":
|
||||
return "customControls_feedbackCommandTemplate";
|
||||
|
|
|
|||
|
|
@ -472,6 +472,7 @@ class MachineCom(object):
|
|||
|
||||
for line in scriptLines:
|
||||
self.sendCommand(line)
|
||||
return "\n".join(scriptLines)
|
||||
|
||||
def startPrint(self):
|
||||
if not self.isOperational() or self.isPrinting():
|
||||
|
|
|
|||
Loading…
Reference in a new issue