First work on custom controls with printer feedback evaluation and presentation in the UI

master
Gina Häußge 2013-06-21 20:50:57 +02:00
parent 5bf5d24dfc
commit f041c6b4f3
5 changed files with 72 additions and 6 deletions

View File

@ -128,6 +128,11 @@ class Printer():
try: callback.sendUpdateTrigger(type)
except: pass
def _sendFeedbackCommandOutput(self, name, output):
for callback in self._callbacks:
try: callback.sendFeedbackCommandOutput(name, output)
except: pass
#~~ printer commands
def connect(self, port=None, baudrate=None):
@ -442,6 +447,9 @@ class Printer():
self._setProgressData(None, None, None, None)
self._stateMonitor.setState({"state": self._state, "stateString": self.getStateString(), "flags": self._getStateFlags()})
def mcReceivedRegisteredMessage(self, command, output):
self._sendFeedbackCommandOutput(command, output)
#~~ sd file handling
def getSdFiles(self):

View File

@ -95,6 +95,9 @@ class PrinterStateConnection(tornadio2.SocketConnection):
def sendUpdateTrigger(self, type):
self.emit("updateTrigger", type)
def sendFeedbackCommandOutput(self, name, output):
self.emit("feedbackCommandOutput", {"name": name, "output": output})
def addLog(self, data):
with self._logBacklogMutex:
self._logBacklog.append(data)

View File

@ -2,11 +2,11 @@
__author__ = "Gina Häußge <osd@foosel.net>"
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
import ConfigParser
import sys
import os
import yaml
import logging
import re
APPNAME="OctoPrint"
@ -204,6 +204,29 @@ class Settings(object):
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
def set(self, path, value, force=False):

View File

@ -525,6 +525,8 @@ function ControlViewModel(loginStateViewModel) {
self.extrusionAmount = ko.observable(undefined);
self.controls = ko.observableArray([]);
self.feedbackControlLookup = {};
self.fromCurrentData = function(data) {
self._processStateData(data.state);
}
@ -543,6 +545,12 @@ function ControlViewModel(loginStateViewModel) {
self.isLoading(data.flags.loading);
}
self._processFeedbackCommandData = function(data) {
if (data.name in self.feedbackControlLookup) {
self.feedbackControlLookup[data.name](data.output);
}
}
self.requestData = function() {
$.ajax({
url: AJAX_BASEURL + "control/custom",
@ -555,23 +563,26 @@ function ControlViewModel(loginStateViewModel) {
}
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++) {
controls[i] = self._enhanceControl(controls[i]);
controls[i] = self._processControl(controls[i]);
}
return controls;
}
self._enhanceControl = function(control) {
self._processControl = function(control) {
if (control.type == "parametric_command" || control.type == "parametric_commands") {
for (var i = 0; i < control.input.length; i++) {
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") {
control.children = self._enhanceControls(control.children);
control.children = self._processControls(control.children);
}
return control;
}
@ -659,6 +670,8 @@ function ControlViewModel(loginStateViewModel) {
case "parametric_command":
case "parametric_commands":
return "customControls_parametricCommandTemplate";
case "feedback_command":
return "customControls_feedbackCommandTemplate";
default:
return "customControls_emptyTemplate";
}

View File

@ -153,6 +153,9 @@ class VirtualPrinter():
# reset current line
self.currentLine = int(re.search('N([0-9]+)', data).group(1))
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:
# simulate a resend at line 100 of the last 5 lines
self.readList.append("Error: Line Number is not Last Line Number\n")
@ -324,6 +327,9 @@ class MachineComPrintCallback(object):
def mcFileTransferStarted(self, filename, filesize):
pass
def mcReceivedRegisteredMessage(self, command, message):
pass
class MachineCom(object):
STATE_NONE = 0
STATE_OPEN_SERIAL = 1
@ -522,6 +528,8 @@ class MachineCom(object):
return ret
def _monitor(self):
feedbackControls = settings().getFeedbackControls()
#Open the serial port.
if self._port == 'AUTO':
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():
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:
heatingUp = False