Workaround for idle temperature polling not working with Repetier Firmware

Repetier always first sends the ok and then any command output. In case of M105, that makes the response look like from an externally triggered heatup (no ok on the same line), causing polling to stop until that falsely detected heatup is complete. Added a configuration option to disable heatup detection. The disadvantage of this is that when printing via Repetier Firmware from SD, the heatup times won't be substractable from the total print time, leading to a less accurate print time left estimation.

 Closes #835
This commit is contained in:
Gina Häußge 2015-04-24 09:36:43 +02:00
parent c6fdab554b
commit 9ee9f7bffb
7 changed files with 45 additions and 13 deletions

View file

@ -393,6 +393,11 @@ Use the following settings to enable or disable OctoPrint features:
# instead of attaching that information to the regular M105 responses
repetierTargetTemp: false
# Whether to enable external heatup detection (to detect heatup triggered e.g. through the printer's LCD panel or
# while printing from SD) or not. Causes issues with Repetier's "first ok then response" approach to
# communication, so disable for printers running Repetier firmware.
externalHeatupDetection: true
# Whether to enable the keyboard control feature in the control tab
keyboardControl: true

View file

@ -59,6 +59,8 @@ class VirtualPrinter():
self._newSdFilePos = None
self._heatupThread = None
self._okBeforeCommandOutput = settings().getBoolean(["devel", "virtualPrinter", "okBeforeCommandOutput"])
self.currentLine = 0
self.lastN = 0
@ -147,14 +149,15 @@ class VirtualPrinter():
self._sendOk()
continue
if len(data.strip()) > 0 and self._okBeforeCommandOutput:
self._sendOk()
#print "Send: %s" % (data.rstrip())
if 'M104' in data or 'M109' in data:
self._parseHotendCommand(data)
continue
if 'M140' in data or 'M190' in data:
self._parseBedCommand(data)
continue
if 'M105' in data:
self._processTemperatureQuery()
@ -197,7 +200,10 @@ class VirtualPrinter():
self._deleteSdFile(filename)
elif "M114" in data:
# send dummy position report
self.outgoing.put("ok C: X:10.00 Y:3.20 Z:5.20 E:1.24")
output = "C: X:10.00 Y:3.20 Z:5.20 E:1.24"
if not self._okBeforeCommandOutput:
output = "ok " + output
self.outgoing.put(output)
continue
elif "M117" in data:
# we'll just use this to echo a message, to allow playing around with pause triggers
@ -259,7 +265,7 @@ class VirtualPrinter():
self.outgoing.put("// sleeping for {interval} seconds".format(interval=interval))
time.sleep(interval)
if len(data.strip()) > 0:
if len(data.strip()) > 0 and not self._okBeforeCommandOutput:
self._sendOk()
def _debugTrigger(self, data):
@ -343,6 +349,7 @@ class VirtualPrinter():
def _processTemperatureQuery(self):
includeTarget = not settings().getBoolean(["devel", "virtualPrinter", "repetierStyleTargetTemperature"])
includeOk = not self._okBeforeCommandOutput
# send simulated temperature data
if settings().getInt(["devel", "virtualPrinter", "numExtruders"]) > 1:
@ -362,16 +369,20 @@ class VirtualPrinter():
if settings().getBoolean(["devel", "virtualPrinter", "includeCurrentToolInTemps"]):
if includeTarget:
self.outgoing.put("ok T:%.2f /%.2f %s @:64\n" % (self.temp[self.currentExtruder], self.targetTemp[self.currentExtruder] + 1, allTempsString))
output = "T:%.2f /%.2f %s @:64\n" % (self.temp[self.currentExtruder], self.targetTemp[self.currentExtruder] + 1, allTempsString)
else:
self.outgoing.put("ok T:%.2f %s @:64\n" % (self.temp[self.currentExtruder], allTempsString))
output = "T:%.2f %s @:64\n" % (self.temp[self.currentExtruder], allTempsString)
else:
self.outgoing.put("ok %s @:64\n" % allTempsString)
output = "%s @:64\n" % allTempsString
else:
if includeTarget:
self.outgoing.put("ok T:%.2f /%.2f B:%.2f /%.2f @:64\n" % (self.temp[0], self.targetTemp[0], self.bedTemp, self.bedTargetTemp))
output = "T:%.2f /%.2f B:%.2f /%.2f @:64\n" % (self.temp[0], self.targetTemp[0], self.bedTemp, self.bedTargetTemp)
else:
self.outgoing.put("ok T:%.2f B:%.2f @:64\n" % (self.temp[0], self.bedTemp))
output = "T:%.2f B:%.2f @:64\n" % (self.temp[0], self.bedTemp)
if includeOk:
output = "ok " + output
self.outgoing.put(output)
def _parseHotendCommand(self, line):
tool = 0

View file

@ -64,6 +64,7 @@ def getSettings():
"sdAlwaysAvailable": s.getBoolean(["feature", "sdAlwaysAvailable"]),
"swallowOkAfterResend": s.getBoolean(["feature", "swallowOkAfterResend"]),
"repetierTargetTemp": s.getBoolean(["feature", "repetierTargetTemp"]),
"externalHeatupDetection": s.getBoolean(["feature", "externalHeatupDetection"]),
"keyboardControl": s.getBoolean(["feature", "keyboardControl"])
},
"serial": {
@ -175,6 +176,7 @@ def setSettings():
if "sdAlwaysAvailable" in data["feature"].keys(): s.setBoolean(["feature", "sdAlwaysAvailable"], data["feature"]["sdAlwaysAvailable"])
if "swallowOkAfterResend" in data["feature"].keys(): s.setBoolean(["feature", "swallowOkAfterResend"], data["feature"]["swallowOkAfterResend"])
if "repetierTargetTemp" in data["feature"].keys(): s.setBoolean(["feature", "repetierTargetTemp"], data["feature"]["repetierTargetTemp"])
if "externalHeatupDetection" in data["feature"].keys(): s.setBoolean(["feature", "externalHeatupDetection"], data["feature"]["externalHeatupDetection"])
if "keyboardControl" in data["feature"].keys(): s.setBoolean(["feature", "keyboardControl"], data["feature"]["keyboardControl"])
if "serial" in data.keys():

View file

@ -136,6 +136,7 @@ default_settings = {
"sdAlwaysAvailable": False,
"swallowOkAfterResend": True,
"repetierTargetTemp": False,
"externalHeatupDetection": True,
"keyboardControl": True
},
"folder": {
@ -255,6 +256,7 @@ default_settings = {
},
"hasBed": True,
"repetierStyleTargetTemperature": False,
"okBeforeCommandOutput": False,
"smoothieTemperatureReporting": False,
"extendedSdFileList": False,
"throttle": 0.01,
@ -501,7 +503,7 @@ class Settings(object):
elif "children" in result:
# if it has children we need to process them recursively
result["children"] = map(process_control, result["children"])
result["children"] = map(process_control, [child for child in result["children"] if child is not None])
return result

View file

@ -79,6 +79,7 @@ $(function() {
self.feature_sdAlwaysAvailable = ko.observable(undefined);
self.feature_swallowOkAfterResend = ko.observable(undefined);
self.feature_repetierTargetTemp = ko.observable(undefined);
self.feature_disableExternalHeatupDetection = ko.observable(undefined);
self.feature_keyboardControl = ko.observable(undefined);
self.serial_port = ko.observable();
@ -227,6 +228,7 @@ $(function() {
self.feature_sdAlwaysAvailable(response.feature.sdAlwaysAvailable);
self.feature_swallowOkAfterResend(response.feature.swallowOkAfterResend);
self.feature_repetierTargetTemp(response.feature.repetierTargetTemp);
self.feature_disableExternalHeatupDetection(!response.feature.externalHeatupDetection);
self.feature_keyboardControl(response.feature.keyboardControl);
self.serial_port(response.serial.port);
@ -303,6 +305,7 @@ $(function() {
"sdAlwaysAvailable": self.feature_sdAlwaysAvailable(),
"swallowOkAfterResend": self.feature_swallowOkAfterResend(),
"repetierTargetTemp": self.feature_repetierTargetTemp(),
"externalHeatupDetection": !self.feature_disableExternalHeatupDetection(),
"keyboardControl": self.feature_keyboardControl()
},
"serial": {

View file

@ -30,14 +30,14 @@
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" data-bind="checked: feature_sdAlwaysAvailable" id="settings-featureSdAlwaysAvailable"> {{ _('Always assume SD card is present') }} <span class="label">{{ _('Repetier') }}</span>
<input type="checkbox" data-bind="checked: feature_waitForStart" id="settings-featureWaitForStart"> {{ _('Wait for <code>start</code> on connect') }}
</label>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" data-bind="checked: feature_waitForStart" id="settings-featureWaitForStart"> {{ _('Wait for <code>start</code> on connect') }}
<input type="checkbox" data-bind="checked: feature_sdAlwaysAvailable" id="settings-featureSdAlwaysAvailable"> {{ _('Always assume SD card is present') }} <span class="label">{{ _('Repetier') }}</span>
</label>
</div>
</div>
@ -55,6 +55,13 @@
</label>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" data-bind="checked: feature_disableExternalHeatupDetection" id="settings-featureExternalHeatupDetection"> {{ _('Disable detection of external heatups') }} <span class="label">{{ _('Repetier') }}</span>
</label>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox">

View file

@ -770,6 +770,8 @@ class MachineCom(object):
feedback_errors = []
pause_triggers = convert_pause_triggers(settings().get(["printerParameters", "pauseTriggers"]))
disable_external_heatup_detection = not settings().getBoolean(["feature", "externalHeatupDetection"])
#Open the serial port.
if not self._openSerial():
return
@ -860,7 +862,7 @@ class MachineCom(object):
##~~ Temperature processing
if ' T:' in line or line.startswith('T:') or ' T0:' in line or line.startswith('T0:'):
if not line.strip().startswith("ok") and not self._heating:
if not disable_external_heatup_detection and not line.strip().startswith("ok") and not self._heating:
self._logger.debug("Externally triggered heatup detected")
self._heating = True
self._heatupWaitStartTime = time.time()