First work on custom controls with printer feedback evaluation and presentation in the UI
parent
5bf5d24dfc
commit
f041c6b4f3
|
@ -128,6 +128,11 @@ class Printer():
|
||||||
try: callback.sendUpdateTrigger(type)
|
try: callback.sendUpdateTrigger(type)
|
||||||
except: pass
|
except: pass
|
||||||
|
|
||||||
|
def _sendFeedbackCommandOutput(self, name, output):
|
||||||
|
for callback in self._callbacks:
|
||||||
|
try: callback.sendFeedbackCommandOutput(name, output)
|
||||||
|
except: pass
|
||||||
|
|
||||||
#~~ printer commands
|
#~~ printer commands
|
||||||
|
|
||||||
def connect(self, port=None, baudrate=None):
|
def connect(self, port=None, baudrate=None):
|
||||||
|
@ -442,6 +447,9 @@ class Printer():
|
||||||
self._setProgressData(None, None, None, None)
|
self._setProgressData(None, None, None, None)
|
||||||
self._stateMonitor.setState({"state": self._state, "stateString": self.getStateString(), "flags": self._getStateFlags()})
|
self._stateMonitor.setState({"state": self._state, "stateString": self.getStateString(), "flags": self._getStateFlags()})
|
||||||
|
|
||||||
|
def mcReceivedRegisteredMessage(self, command, output):
|
||||||
|
self._sendFeedbackCommandOutput(command, output)
|
||||||
|
|
||||||
#~~ sd file handling
|
#~~ sd file handling
|
||||||
|
|
||||||
def getSdFiles(self):
|
def getSdFiles(self):
|
||||||
|
|
|
@ -95,6 +95,9 @@ class PrinterStateConnection(tornadio2.SocketConnection):
|
||||||
def sendUpdateTrigger(self, type):
|
def sendUpdateTrigger(self, type):
|
||||||
self.emit("updateTrigger", type)
|
self.emit("updateTrigger", type)
|
||||||
|
|
||||||
|
def sendFeedbackCommandOutput(self, name, output):
|
||||||
|
self.emit("feedbackCommandOutput", {"name": name, "output": output})
|
||||||
|
|
||||||
def addLog(self, data):
|
def addLog(self, data):
|
||||||
with self._logBacklogMutex:
|
with self._logBacklogMutex:
|
||||||
self._logBacklog.append(data)
|
self._logBacklog.append(data)
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
__author__ = "Gina Häußge <osd@foosel.net>"
|
__author__ = "Gina Häußge <osd@foosel.net>"
|
||||||
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
|
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
|
||||||
|
|
||||||
import ConfigParser
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import yaml
|
import yaml
|
||||||
import logging
|
import logging
|
||||||
|
import re
|
||||||
|
|
||||||
APPNAME="OctoPrint"
|
APPNAME="OctoPrint"
|
||||||
|
|
||||||
|
@ -204,6 +204,29 @@ class Settings(object):
|
||||||
|
|
||||||
return folder
|
return folder
|
||||||
|
|
||||||
|
def getFeedbackControls(self):
|
||||||
|
feedbackControls = []
|
||||||
|
for control in self.get(["controls"]):
|
||||||
|
feedbackControls.extend(self._getFeedbackControls(control))
|
||||||
|
return feedbackControls
|
||||||
|
|
||||||
|
def _getFeedbackControls(self, control=None):
|
||||||
|
if control["type"] == "feedback_command":
|
||||||
|
pattern = control["regex"]
|
||||||
|
try:
|
||||||
|
matcher = re.compile(pattern)
|
||||||
|
return [(control["name"], matcher, control["template"])]
|
||||||
|
except:
|
||||||
|
# invalid regex or something like this, we'll just skip this entry
|
||||||
|
pass
|
||||||
|
elif control["type"] == "section":
|
||||||
|
result = []
|
||||||
|
for c in control["children"]:
|
||||||
|
result.extend(self._getFeedbackControls(c))
|
||||||
|
return result
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
|
||||||
#~~ setter
|
#~~ setter
|
||||||
|
|
||||||
def set(self, path, value, force=False):
|
def set(self, path, value, force=False):
|
||||||
|
|
|
@ -525,6 +525,8 @@ function ControlViewModel(loginStateViewModel) {
|
||||||
self.extrusionAmount = ko.observable(undefined);
|
self.extrusionAmount = ko.observable(undefined);
|
||||||
self.controls = ko.observableArray([]);
|
self.controls = ko.observableArray([]);
|
||||||
|
|
||||||
|
self.feedbackControlLookup = {};
|
||||||
|
|
||||||
self.fromCurrentData = function(data) {
|
self.fromCurrentData = function(data) {
|
||||||
self._processStateData(data.state);
|
self._processStateData(data.state);
|
||||||
}
|
}
|
||||||
|
@ -543,6 +545,12 @@ function ControlViewModel(loginStateViewModel) {
|
||||||
self.isLoading(data.flags.loading);
|
self.isLoading(data.flags.loading);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self._processFeedbackCommandData = function(data) {
|
||||||
|
if (data.name in self.feedbackControlLookup) {
|
||||||
|
self.feedbackControlLookup[data.name](data.output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.requestData = function() {
|
self.requestData = function() {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: AJAX_BASEURL + "control/custom",
|
url: AJAX_BASEURL + "control/custom",
|
||||||
|
@ -555,23 +563,26 @@ function ControlViewModel(loginStateViewModel) {
|
||||||
}
|
}
|
||||||
|
|
||||||
self._fromResponse = function(response) {
|
self._fromResponse = function(response) {
|
||||||
self.controls(self._enhanceControls(response.controls));
|
self.controls(self._processControls(response.controls));
|
||||||
}
|
}
|
||||||
|
|
||||||
self._enhanceControls = function(controls) {
|
self._processControls = function(controls) {
|
||||||
for (var i = 0; i < controls.length; i++) {
|
for (var i = 0; i < controls.length; i++) {
|
||||||
controls[i] = self._enhanceControl(controls[i]);
|
controls[i] = self._processControl(controls[i]);
|
||||||
}
|
}
|
||||||
return controls;
|
return controls;
|
||||||
}
|
}
|
||||||
|
|
||||||
self._enhanceControl = function(control) {
|
self._processControl = function(control) {
|
||||||
if (control.type == "parametric_command" || control.type == "parametric_commands") {
|
if (control.type == "parametric_command" || control.type == "parametric_commands") {
|
||||||
for (var i = 0; i < control.input.length; i++) {
|
for (var i = 0; i < control.input.length; i++) {
|
||||||
control.input[i].value = control.input[i].default;
|
control.input[i].value = control.input[i].default;
|
||||||
}
|
}
|
||||||
|
} else if (control.type == "feedback_command") {
|
||||||
|
control.output = ko.observable("");
|
||||||
|
self.feedbackControlLookup[control.name] = control.output;
|
||||||
} else if (control.type == "section") {
|
} else if (control.type == "section") {
|
||||||
control.children = self._enhanceControls(control.children);
|
control.children = self._processControls(control.children);
|
||||||
}
|
}
|
||||||
return control;
|
return control;
|
||||||
}
|
}
|
||||||
|
@ -659,6 +670,8 @@ function ControlViewModel(loginStateViewModel) {
|
||||||
case "parametric_command":
|
case "parametric_command":
|
||||||
case "parametric_commands":
|
case "parametric_commands":
|
||||||
return "customControls_parametricCommandTemplate";
|
return "customControls_parametricCommandTemplate";
|
||||||
|
case "feedback_command":
|
||||||
|
return "customControls_feedbackCommandTemplate";
|
||||||
default:
|
default:
|
||||||
return "customControls_emptyTemplate";
|
return "customControls_emptyTemplate";
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,6 +153,9 @@ class VirtualPrinter():
|
||||||
# reset current line
|
# reset current line
|
||||||
self.currentLine = int(re.search('N([0-9]+)', data).group(1))
|
self.currentLine = int(re.search('N([0-9]+)', data).group(1))
|
||||||
self.readList.append("ok\n")
|
self.readList.append("ok\n")
|
||||||
|
elif "M114" in data:
|
||||||
|
# send dummy position report
|
||||||
|
self.readList.append("ok C: X:10.00 Y:3.20 Z:5.20 E:1.24")
|
||||||
elif self.currentLine == 100:
|
elif self.currentLine == 100:
|
||||||
# simulate a resend at line 100 of the last 5 lines
|
# simulate a resend at line 100 of the last 5 lines
|
||||||
self.readList.append("Error: Line Number is not Last Line Number\n")
|
self.readList.append("Error: Line Number is not Last Line Number\n")
|
||||||
|
@ -324,6 +327,9 @@ class MachineComPrintCallback(object):
|
||||||
def mcFileTransferStarted(self, filename, filesize):
|
def mcFileTransferStarted(self, filename, filesize):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def mcReceivedRegisteredMessage(self, command, message):
|
||||||
|
pass
|
||||||
|
|
||||||
class MachineCom(object):
|
class MachineCom(object):
|
||||||
STATE_NONE = 0
|
STATE_NONE = 0
|
||||||
STATE_OPEN_SERIAL = 1
|
STATE_OPEN_SERIAL = 1
|
||||||
|
@ -522,6 +528,8 @@ class MachineCom(object):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def _monitor(self):
|
def _monitor(self):
|
||||||
|
feedbackControls = settings().getFeedbackControls()
|
||||||
|
|
||||||
#Open the serial port.
|
#Open the serial port.
|
||||||
if self._port == 'AUTO':
|
if self._port == 'AUTO':
|
||||||
self._changeState(self.STATE_DETECT_SERIAL)
|
self._changeState(self.STATE_DETECT_SERIAL)
|
||||||
|
@ -668,6 +676,17 @@ class MachineCom(object):
|
||||||
elif line.strip() != '' and line.strip() != 'ok' and not line.startswith("wait") and not line.startswith('Resend:') and line != 'echo:Unknown command:""\n' and self.isOperational():
|
elif line.strip() != '' and line.strip() != 'ok' and not line.startswith("wait") and not line.startswith('Resend:') and line != 'echo:Unknown command:""\n' and self.isOperational():
|
||||||
self._callback.mcMessage(line)
|
self._callback.mcMessage(line)
|
||||||
|
|
||||||
|
##~~ Parsing for feedback commands
|
||||||
|
if feedbackControls:
|
||||||
|
for name, matcher, template in feedbackControls:
|
||||||
|
try:
|
||||||
|
match = matcher.search(line)
|
||||||
|
if match is not None:
|
||||||
|
self._callback.mcReceivedRegisteredMessage(name, template % match.groups("n/a"))
|
||||||
|
except:
|
||||||
|
# ignored on purpose
|
||||||
|
pass
|
||||||
|
|
||||||
if "ok" in line and heatingUp:
|
if "ok" in line and heatingUp:
|
||||||
heatingUp = False
|
heatingUp = False
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue