Allow definition of gcode scripts to be sent to the printer at various stages of the print process

This commit is contained in:
Gina Häußge 2014-10-30 12:20:48 +01:00
parent f8955c0d1b
commit b7a9be31eb
9 changed files with 154 additions and 77 deletions

View file

@ -288,7 +288,7 @@ class Printer():
self._comm.setPause(not self._comm.isPaused())
def cancelPrint(self, disableMotorsAndHeater=True):
def cancelPrint(self):
"""
Cancel the current printjob.
"""
@ -297,13 +297,6 @@ class Printer():
self._comm.cancelPrint()
if disableMotorsAndHeater:
# disable motors, switch off hotends, bed and fan
commands = ["M84"]
commands.extend(map(lambda x: "M104 T%d S0" % x, range(settings().getInt(["printerParameters", "numExtruders"]))))
commands.extend(["M140 S0", "M106 S0"])
self.commands(commands)
# reset progress, height, print time
self._setCurrentZ(None)
self._setProgressData(None, None, None, None)

View file

@ -99,11 +99,7 @@ def getSettings():
"events": s.get(["system", "events"])
},
"terminalFilters": s.get(["terminalFilters"]),
"cura": {
"enabled": s.getBoolean(["cura", "enabled"]),
"path": s.get(["cura", "path"]),
"config": s.get(["cura", "config"])
}
"scripts": s.get(["scripts"])
}
def process_plugin_result(name, plugin, result):
@ -206,19 +202,8 @@ def setSettings():
if "actions" in data["system"].keys(): s.set(["system", "actions"], data["system"]["actions"])
if "events" in data["system"].keys(): s.set(["system", "events"], data["system"]["events"])
cura = data.get("cura", None)
if cura:
path = cura.get("path")
if path:
s.set(["cura", "path"], path)
config = cura.get("config")
if config:
s.set(["cura", "config"], config)
# Enabled is a boolean so we cannot check that we have a result
enabled = cura.get("enabled")
s.setBoolean(["cura", "enabled"], enabled)
if "scripts" in data:
if "gcode" in data["scripts"]: s.set(["scripts", "gcode"], data["scripts"]["gcode"])
if "plugins" in data:
for name, plugin in octoprint.plugin.plugin_manager().get_implementations(octoprint.plugin.SettingsPlugin).items():

View file

@ -161,6 +161,15 @@ default_settings = {
{ "name": "Suppress M27 requests/responses", "regex": "(Send: M27)|(Recv: SD printing byte)" }
],
"plugins": {},
"scripts": {
"gcode": {
"beforePrintStarted": None,
"afterPrintDone": None,
"afterPrintCancelled": None,
"afterPrintPaused": None,
"beforePrintResumed": None
}
},
"devel": {
"stylesheet": "css",
"virtualPrinter": {

File diff suppressed because one or more lines are too long

View file

@ -59,7 +59,7 @@ $(function() {
settingsDialog.modal()
.css({
width: 'auto',
'margin-left': function() { return -($(this).width() /2); }
'margin-left': function() { return -($(this).width() / 2); }
});
return false;

View file

@ -157,9 +157,11 @@ function SettingsViewModel(loginStateViewModel, usersViewModel) {
self.folder_logs = ko.observable(undefined);
self.folder_watched = ko.observable(undefined);
self.cura_enabled = ko.observable(undefined);
self.cura_path = ko.observable(undefined);
self.cura_config = ko.observable(undefined);
self.scripts_gcode_beforePrintStarted = ko.observable(undefined);
self.scripts_gcode_afterPrintDone = ko.observable(undefined);
self.scripts_gcode_afterPrintCancelled = ko.observable(undefined);
self.scripts_gcode_afterPrintPaused = ko.observable(undefined);
self.scripts_gcode_beforePrintResumed = ko.observable(undefined);
self.temperature_profiles = ko.observableArray(undefined);
@ -281,9 +283,11 @@ function SettingsViewModel(loginStateViewModel, usersViewModel) {
self.folder_logs(response.folder.logs);
self.folder_watched(response.folder.watched);
self.cura_enabled(response.cura.enabled);
self.cura_path(response.cura.path);
self.cura_config(response.cura.config);
self.scripts_gcode_beforePrintStarted(response.scripts.gcode.beforePrintStarted);
self.scripts_gcode_afterPrintDone(response.scripts.gcode.afterPrintDone);
self.scripts_gcode_afterPrintCancelled(response.scripts.gcode.afterPrintCancelled);
self.scripts_gcode_afterPrintPaused(response.scripts.gcode.afterPrintPaused);
self.scripts_gcode_beforePrintResumed(response.scripts.gcode.beforePrintResumed);
self.temperature_profiles(response.temperature.profiles);
@ -359,12 +363,16 @@ function SettingsViewModel(loginStateViewModel, usersViewModel) {
"system": {
"actions": self.system_actions()
},
"cura": {
"enabled": self.cura_enabled(),
"path": self.cura_path(),
"config": self.cura_config()
},
"terminalFilters": self.terminalFilters()
"terminalFilters": self.terminalFilters(),
"scripts": {
"gcode": {
"beforePrintStarted": self.scripts_gcode_beforePrintStarted(),
"afterPrintDone": self.scripts_gcode_afterPrintDone(),
"afterPrintCancelled": self.scripts_gcode_afterPrintCancelled(),
"afterPrintPaused": self.scripts_gcode_afterPrintPaused(),
"beforePrintResumed": self.scripts_gcode_beforePrintResumed()
}
}
});
$.ajax({

View file

@ -599,7 +599,16 @@ ul.dropdown-menu li a {
overflow: visible !important;
}
.border_box {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
textarea.block {
.border_box;
width: 100%;
}
#drop_overlay {
position: fixed;

View file

@ -1,16 +1,17 @@
<div id="settings_dialog" class="modal hide fade container" tabindex="-1" role="dialog" aria-labelledby="settings_dialog_label" aria-hidden="true">
<div id="settings_dialog" class="modal hide fade container" tabindex="-1" role="dialog" aria-labelledby="settings_dialog_label" aria-hidden="true" data-replace="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h3 id="settings_dialog_label">{{ _('OctoPrint Settings') }}</h3>
</div>
<div class="modal-body">
<div class="tabbable">
<ul class="nav nav-list span4" id="settingsTabs">
<ul class="nav nav-list span3" id="settingsTabs">
<li class="nav-header">{{ _('Printer') }}</li>
<li class="active"><a href="#settings_serialConnection" data-toggle="tab">{{ _('Serial Connection') }}</a></li>
<li><a href="#settings_printerParameters" data-toggle="tab">{{ _('Printer Parameters') }}</a></li>
<li><a href="#settings_temperature" data-toggle="tab">{{ _('Temperatures') }}</a></li>
<li><a href="#settings_terminalFilters" data-toggle="tab">{{ _('Terminal filters') }}</a></li>
<li><a href="#settings_gcodeScripts" data-toggle="tab">{{ _('GCODE Scripts') }}</a></li>
<li class="nav-header">{{ _('Features') }}</li>
<li><a href="#settings_features" data-toggle="tab">{{ _('Features') }}</a></li>
<li><a href="#settings_webcam" data-toggle="tab">{{ _('Webcam') }}</a></li>
@ -30,7 +31,7 @@
{% endif %}
</ul>
<div class="tab-content span8">
<div class="tab-content span9">
<div class="tab-pane active" id="settings_serialConnection">
<form class="form-horizontal">
<div class="control-group">
@ -404,6 +405,40 @@
</div>
</form>
</div>
<div class="tab-pane" id="settings_gcodeScripts">
<form class="form-horizontal">
<div class="control-group">
<label class="control-label">{{ _('Before print job starts') }}</label>
<div class="controls">
<textarea rows="3" class="block" data-bind="value: scripts_gcode_beforePrintStarted"></textarea>
</div>
</div>
<div class="control-group">
<label class="control-label">{{ _('After print job completes') }}</label>
<div class="controls">
<textarea rows="3" class="block" data-bind="value: scripts_gcode_afterPrintDone"></textarea>
</div>
</div>
<div class="control-group">
<label class="control-label">{{ _('After print job is cancelled') }}</label>
<div class="controls">
<textarea rows="3" class="block" data-bind="value: scripts_gcode_afterPrintCancelled"></textarea>
</div>
</div>
<div class="control-group">
<label class="control-label">{{ _('After print job is paused') }}</label>
<div class="controls">
<textarea rows="3" class="block" data-bind="value: scripts_gcode_afterPrintPaused"></textarea>
</div>
</div>
<div class="control-group">
<label class="control-label">{{ _('Before print job is resumed') }}</label>
<div class="controls">
<textarea rows="3" class="block" data-bind="value: scripts_gcode_beforePrintResumed"></textarea>
</div>
</div>
</form>
</div>
<div class="tab-pane" id="settings_appearance">
<form class="form-horizontal">
<div class="control-group">

View file

@ -381,6 +381,24 @@ class MachineCom(object):
elif self.isOperational():
self._sendCommand(cmd)
def sendGcodeScript(self, scriptName):
gcodeScripts = settings().get(["scripts", "gcode"])
if scriptName in gcodeScripts and gcodeScripts[scriptName] is not None:
script = gcodeScripts[scriptName]
else:
if scriptName == "afterPrintCancelled":
commands = ["M84"]
commands.extend(map(lambda x: "M104 T%d S0" % x, range(settings().getInt(["printerParameters", "numExtruders"]))))
commands.extend(["M140 S0", "M106 S0"])
script = "\n".join(commands)
else:
return
scriptLines = map(str.strip, script.split("\n"))
for line in scriptLines:
self.sendCommand(line)
def startPrint(self):
if not self.isOperational() or self.isPrinting():
return
@ -399,13 +417,17 @@ class MachineCom(object):
"origin": self._currentFile.getFileLocation()
})
self.sendGcodeScript("beforePrintStarted")
if self.isSdFileSelected():
if wasPaused:
self.sendCommand("M26 S0")
self._currentFile.setFilepos(0)
self.sendCommand("M24")
else:
self._sendNext()
line = self._getNext()
if line is not None:
self.sendCommand(line)
except:
self._logger.exception("Error while trying to start printing")
self._errorValue = getExceptionString()
@ -459,6 +481,8 @@ class MachineCom(object):
self.sendCommand("M25") # pause print
self.sendCommand("M26 S0") # reset position in file to byte 0
self.sendGcodeScript("afterPrintCancelled")
eventManager().fire(Events.PRINT_CANCELLED, {
"file": self._currentFile.getFilename(),
"filename": os.path.basename(self._currentFile.getFilename()),
@ -471,10 +495,13 @@ class MachineCom(object):
if not pause and self.isPaused():
self._changeState(self.STATE_PRINTING)
self.sendGcodeScript("beforePrintResumed")
if self.isSdFileSelected():
self.sendCommand("M24")
else:
self._sendNext()
line = self._getNext()
if line is not None:
self.sendCommand(line)
eventManager().fire(Events.PRINT_RESUMED, {
"file": self._currentFile.getFilename(),
@ -485,6 +512,7 @@ class MachineCom(object):
self._changeState(self.STATE_PAUSED)
if self.isSdFileSelected():
self.sendCommand("M25") # pause print
self.sendGcodeScript("afterPrintPaused")
eventManager().fire(Events.PRINT_PAUSED, {
"file": self._currentFile.getFilename(),
@ -878,8 +906,12 @@ class MachineCom(object):
### Operational
elif self._state == self.STATE_OPERATIONAL or self._state == self.STATE_PAUSED:
# if we still have commands to process, process them
if "ok" in line and not self._commandQueue.empty():
self._sendCommand(self._commandQueue.get())
#Request the temperature on comm timeout (every 5 seconds) when we are not printing.
if line == "" or "wait" in line:
elif line == "" or "wait" in line:
if self._resendDelta is not None:
self._resendNextCommand()
elif not self._commandQueue.empty():
@ -887,6 +919,7 @@ class MachineCom(object):
else:
self._sendCommand("M105")
tempRequestTimeout = getNewTimeout("temperature")
# resend -> start resend procedure from requested line
elif line.lower().startswith("resend") or line.lower().startswith("rs"):
if settings().get(["feature", "swallowOkAfterResend"]):
@ -1018,39 +1051,44 @@ class MachineCom(object):
self._log("Recv: %s" % sanitizeAscii(ret))
return ret
def _getNext(self):
line = self._currentFile.getNext()
if line is None:
if self.isStreaming():
self._sendCommand("M29")
remote = self._currentFile.getRemoteFilename()
payload = {
"local": self._currentFile.getLocalFilename(),
"remote": remote,
"time": self.getPrintTime()
}
self._currentFile = None
self._changeState(self.STATE_OPERATIONAL)
self._callback.mcFileTransferDone(remote)
eventManager().fire(Events.TRANSFER_DONE, payload)
self.refreshSdFiles()
else:
payload = {
"file": self._currentFile.getFilename(),
"filename": os.path.basename(self._currentFile.getFilename()),
"origin": self._currentFile.getFileLocation(),
"time": self.getPrintTime()
}
self._callback.mcPrintjobDone()
self._changeState(self.STATE_OPERATIONAL)
eventManager().fire(Events.PRINT_DONE, payload)
self.sendGcodeScript("afterPrintDone")
return line
def _sendNext(self):
with self._sendNextLock:
line = self._currentFile.getNext()
if line is None:
if self.isStreaming():
self._sendCommand("M29")
remote = self._currentFile.getRemoteFilename()
payload = {
"local": self._currentFile.getLocalFilename(),
"remote": remote,
"time": self.getPrintTime()
}
self._currentFile = None
self._changeState(self.STATE_OPERATIONAL)
self._callback.mcFileTransferDone(remote)
eventManager().fire(Events.TRANSFER_DONE, payload)
self.refreshSdFiles()
else:
payload = {
"file": self._currentFile.getFilename(),
"filename": os.path.basename(self._currentFile.getFilename()),
"origin": self._currentFile.getFileLocation(),
"time": self.getPrintTime()
}
self._callback.mcPrintjobDone()
self._changeState(self.STATE_OPERATIONAL)
eventManager().fire(Events.PRINT_DONE, payload)
return
self._sendCommand(line, True)
self._callback.mcProgress()
line = self._getNext()
if line is not None:
self._sendCommand(line, True)
self._callback.mcProgress()
def _handleResendRequest(self, line):
lineToResend = None