Merge branch 'improve/temperatureInScripts' into maintenance

# Conflicts:
#	src/octoprint/util/comm.py
This commit is contained in:
Gina Häußge 2017-06-22 12:45:50 +02:00
commit b34fc8e05e
2 changed files with 114 additions and 64 deletions

View file

@ -68,7 +68,16 @@ All GCODE scripts have access to the following template variables through the te
* ``printer_profile``: The currently selected Printer Profile, including
information such as the extruder count, the build volume size, the filament diameter etc.
* ``last_position``: Last position reported by the printer via `M114` (might be unset if no `M114` was sent so far!)
* ``last_position``: Last position reported by the printer via `M114` (might be unset if no `M114` was sent so far!).
Consists of ``x``, ``y``, ``z`` and ``e`` coordinates as received by the printer and tracked values for ``f`` and
current tool ``t`` taken from commands sent through OctoPrint. All of these coordinates might be ``None`` if no
position could be retrieved from the printer or the values could not be tracked (in case of ``f`` and ``t``)!
* ``last_temperatures``: Last actual and target temperature reported for all available tools and if available the
heated bed. This is a dictionary of key-value pairs. The keys are the indices of the available tools (``0``, ``1``,
...) and ``b`` for the heated bed. The values are a dictionary consisting of ``actual`` and ``target`` keys mapped
to the corresponding temperature in degrees celsius. Note that not all tools your printer has must necessarily be
present here, neither must the heated bed - it depends on whether OctoPrint has values for a tool or the bed. Also
note that ``actual`` and ``target`` might be ``None``.
* ``script``: An object wrapping the script's type (``gcode``) and name (e.g. ``afterPrintCancelled``) as ``script.type``
and ``script.name`` respectively.
@ -76,17 +85,18 @@ There are a few additional template variables available for the following specif
* ``afterPrintPaused`` and ``beforePrintResumed``
* ``pause_position``: Position reported by the printer via ``M114`` immediately before the print was paused. Consists
of ``x``, ``y``, ``z`` and ``e`` coordinates as received by the printer and tracked values for ``f`` and current tool
``t`` taken from commands sent through OctoPrint. All of these coordinates might be ``None`` if no position could be
retrieved from the printer or the values could not be tracked (in case of ``f`` and ``t``)!
* ``pause_position``: Position reported by the printer via ``M114`` immediately before the print was paused. See
``last_position`` above for the structure to expect here.
* ``pause_temperature``: Last known temperature values when the print was paused. See ``last_temperature`` above
for the structure to expect here.
* ``afterPrintCancelled``
* ``cancel_position``: Position reported by the printer via ``M114`` immediately before the print was cancelled.
Consists of ``x``, ``y``, ``z`` and ``e`` coordinates as received by the printer and tracked values for ``f`` and
current tool ``t`` taken from commands sent through OctoPrint. All of these coordinates might be ``None`` if no
position could be retrieved from the printer or the values could not be tracked (in case of ``f`` and ``t``)!
See ``last_position`` above for the structure to expect here.
* ``cancel_temperature``: Last known temperature values when the print was cancelled. See ``last_temperature`` above
for the structure to expect here.
.. warning::

View file

@ -19,6 +19,7 @@ from past.builtins import basestring
import logging
import serial
import octoprint.plugin
from collections import deque
@ -241,6 +242,62 @@ class PositionRecord(object):
t=self.t,
f=self.f)
class TemperatureRecord(object):
def __init__(self):
self._tools = dict()
self._bed = (None, None)
def copy_from(self, other):
self._tools = other.tools
self._bed = other.bed
def set_tool(self, tool, actual=None, target=None):
current = self._tools.get(tool, (None, None))
self._tools[tool] = self._to_new_tuple(current, actual, target)
def set_bed(self, actual=None, target=None):
current = self._bed
self._bed = self._to_new_tuple(current, actual, target)
@property
def tools(self):
return dict(self._tools)
@property
def bed(self):
return self._bed
def as_script_dict(self):
result = dict()
tools = self.tools
for tool, data in tools.items():
result[tool] = dict(actual=data[0],
target=data[1])
bed = self.bed
result["b"] = dict(actual=bed[0],
target=bed[1])
return result
@classmethod
def _to_new_tuple(cls, current, actual, target):
if current is None or not isinstance(current, tuple) or len(current) != 2:
current = (None, None)
if actual is None and target is None:
return current
old_actual, old_target = current
if actual is None:
return old_actual, target
elif target is None:
return actual, old_target
else:
return actual, target
class MachineCom(object):
STATE_NONE = 0
STATE_OPEN_SERIAL = 1
@ -280,8 +337,6 @@ class MachineCom(object):
self._serial = None
self._baudrateDetectList = baudrateList()
self._baudrateDetectRetry = 0
self._temp = {}
self._bedTemp = None
self._temperatureTargetSetThreshold = 25
self._tempOffsets = dict()
self._command_queue = TypedQueue()
@ -395,11 +450,16 @@ class MachineCom(object):
self._ignore_select = False
self._manualStreaming = False
self.last_temperature = TemperatureRecord()
self.pause_temperature = TemperatureRecord()
self.cancel_temperature = TemperatureRecord()
self.last_position = PositionRecord()
self.pause_position = PositionRecord()
self._record_pause_position = False
self.cancel_position = PositionRecord()
self._record_cancel_position = False
self._record_pause_data = False
self._record_cancel_data = False
# print job
self._currentFile = None
@ -578,10 +638,10 @@ class MachineCom(object):
return cleanedPrintTime
def getTemp(self):
return self._temp
return self.last_temperature.tools
def getBedTemp(self):
return self._bedTemp
return self.last_temperature.bed
def getOffsets(self):
return dict(self._tempOffsets)
@ -698,15 +758,19 @@ class MachineCom(object):
context = dict()
if replacements is not None and isinstance(replacements, dict):
context.update(replacements)
context.update(dict(
printer_profile=self._printerProfileManager.get_current_or_default(),
last_position=self.last_position
last_position=self.last_position,
last_temperatures=self.last_temperature.as_script_dict()
))
if scriptName == "afterPrintPaused" or scriptName == "beforePrintResumed":
context.update(dict(pause_position=self.pause_position))
context.update(dict(pause_position=self.pause_position,
pause_temperature=self.pause_temperature.as_script_dict()))
elif scriptName == "afterPrintCancelled":
context.update(dict(cancel_position=self.cancel_position))
context.update(dict(cancel_position=self.cancel_position,
cancel_temperature=self.cancel_temperature.as_script_dict()))
template = settings().loadScript("gcode", scriptName, context=context)
if template is None:
@ -863,7 +927,7 @@ class MachineCom(object):
# we don't call on_print_job_cancelled on our callback here
# because we do this only after our M114 has been answered
# by the firmware
self._record_cancel_position = True
self._record_cancel_data = True
self.sendCommand("M114")
with self._jobLock:
@ -923,7 +987,7 @@ class MachineCom(object):
# we don't call on_print_job_paused on our callback here
# because we do this only after our M114 has been answered
# by the firmware
self._record_pause_position = True
self._record_pause_data = True
self.sendCommand("M114")
self.sendCommand("M400", on_sent=_on_M400_sent)
@ -1024,24 +1088,12 @@ class MachineCom(object):
continue
actual, target = parsedTemps[tool]
if target is not None:
self._temp[n] = (actual, target)
elif n in self._temp and self._temp[n] is not None and isinstance(self._temp[n], tuple):
(oldActual, oldTarget) = self._temp[n]
self._temp[n] = (actual, oldTarget)
else:
self._temp[n] = (actual, None)
self.last_temperature.set_tool(n, actual=actual, target=target)
# bed temperature
if "B" in parsedTemps.keys():
actual, target = parsedTemps["B"]
if target is not None:
self._bedTemp = (actual, target)
elif self._bedTemp is not None and isinstance(self._bedTemp, tuple):
(oldActual, oldTarget) = self._bedTemp
self._bedTemp = (actual, oldTarget)
else:
self._bedTemp = (actual, None)
self.last_temperature.set_bed(actual=actual, target=target)
##~~ Serial monitor processing received messages
@ -1204,16 +1256,18 @@ class MachineCom(object):
reason = None
if self._record_pause_position:
if self._record_pause_data:
reason = "pause"
self._record_pause_position = False
self._record_pause_data = False
self.pause_position.copy_from(self.last_position)
self.pause_temperature.copy_from(self.last_temperature)
self._pause_preparation_done()
if self._record_cancel_position:
if self._record_cancel_data:
reason = "cancel"
self._record_cancel_position = False
self._record_cancel_data = False
self.cancel_position.copy_from(self.last_position)
self.cancel_temperature.copy_from(self.last_temperature)
self._cancel_preparation_done()
self._callback.on_comm_position_update(self.last_position.as_dict(), reason=reason)
@ -1230,7 +1284,7 @@ class MachineCom(object):
self._heatupWaitStartTime = time.time()
self._processTemperatures(line)
self._callback.on_comm_temperature_update(self._temp, self._bedTemp)
self._callback.on_comm_temperature_update(self.last_temperature.tools, self.last_temperature.bed)
elif supportRepetierTargetTemp and ('TargetExtr' in line or 'TargetBed' in line):
matchExtr = regex_repetierTempExtr.match(line)
@ -1240,23 +1294,15 @@ class MachineCom(object):
toolNum = int(matchExtr.group(1))
try:
target = float(matchExtr.group(2))
if toolNum in self._temp.keys() and self._temp[toolNum] is not None and isinstance(self._temp[toolNum], tuple):
(actual, oldTarget) = self._temp[toolNum]
self._temp[toolNum] = (actual, target)
else:
self._temp[toolNum] = (None, target)
self._callback.on_comm_temperature_update(self._temp, self._bedTemp)
self.last_temperature.set_tool(toolNum, target=target)
self._callback.on_comm_temperature_update(self.last_temperature.tools, self.last_temperature.bed)
except ValueError:
pass
elif matchBed is not None:
try:
target = float(matchBed.group(1))
if self._bedTemp is not None and isinstance(self._bedTemp, tuple):
(actual, oldTarget) = self._bedTemp
self._bedTemp = (actual, target)
else:
self._bedTemp = (None, target)
self._callback.on_comm_temperature_update(self._temp, self._bedTemp)
self.last_temperature.set_bed(target=target)
self._callback.on_comm_temperature_update(self.last_temperature.tools, self.last_temperature.bed)
except ValueError:
pass
@ -1691,11 +1737,13 @@ class MachineCom(object):
if self.isBusy():
return self._timeout_intervals.get("temperature", busy_default)
for temp in [self._temp[k][1] for k in self._temp.keys()]:
tools = self.last_temperature.tools
for temp in [tools[k][1] for k in tools.keys()]:
if temp > self._temperatureTargetSetThreshold:
return self._timeout_intervals.get("temperatureTargetSet", target_default)
if self._bedTemp and len(self._bedTemp) > 0 and self._bedTemp[1] > self._temperatureTargetSetThreshold:
bed = self.last_temperature.bed
if bed and len(bed) > 0 and bed[1] > self._temperatureTargetSetThreshold:
return self._timeout_intervals.get("temperatureTargetSet", target_default)
return self._timeout_intervals.get("temperature", busy_default)
@ -2474,12 +2522,8 @@ class MachineCom(object):
if match:
try:
target = float(match.group("value"))
if toolNum in self._temp.keys() and self._temp[toolNum] is not None and isinstance(self._temp[toolNum], tuple):
(actual, oldTarget) = self._temp[toolNum]
self._temp[toolNum] = (actual, target)
else:
self._temp[toolNum] = (None, target)
self._callback.on_comm_temperature_update(self._temp, self._bedTemp)
self.last_temperature.set_tool(toolNum, target=target)
self._callback.on_comm_temperature_update(self.last_temperature.tools, self.last_temperature.bed)
except ValueError:
pass
@ -2491,12 +2535,8 @@ class MachineCom(object):
if match:
try:
target = float(match.group("value"))
if self._bedTemp is not None and isinstance(self._bedTemp, tuple):
(actual, oldTarget) = self._bedTemp
self._bedTemp = (actual, target)
else:
self._bedTemp = (None, target)
self._callback.on_comm_temperature_update(self._temp, self._bedTemp)
self.last_temperature.set_bed(target=target)
self._callback.on_comm_temperature_update(self.last_temperature.tools, self.last_temperature.bed)
except ValueError:
pass