commit
b3b11174be
15 changed files with 217 additions and 71 deletions
|
|
@ -613,11 +613,12 @@ class Printer():
|
|||
"target": self._temp[tool][1],
|
||||
"offset": tempOffset[tool] if tool in tempOffset.keys() and tempOffset[tool] is not None else 0
|
||||
}
|
||||
result["bed"] = {
|
||||
"actual": self._bedTemp[0],
|
||||
"target": self._bedTemp[1],
|
||||
"offset": bedTempOffset
|
||||
}
|
||||
if self._bedTemp is not None:
|
||||
result["bed"] = {
|
||||
"actual": self._bedTemp[0],
|
||||
"target": self._bedTemp[1],
|
||||
"offset": bedTempOffset
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
|
|
|
|||
|
|
@ -71,6 +71,8 @@ def getSettings():
|
|||
"timeoutConnection": s.getFloat(["serial", "timeout", "connection"]),
|
||||
"timeoutDetection": s.getFloat(["serial", "timeout", "detection"]),
|
||||
"timeoutCommunication": s.getFloat(["serial", "timeout", "communication"]),
|
||||
"timeoutTemperature": s.getFloat(["serial", "timeout", "temperature"]),
|
||||
"timeoutSdStatus": s.getFloat(["serial", "timeout", "sdStatus"]),
|
||||
"log": s.getBoolean(["serial", "log"])
|
||||
},
|
||||
"folder": {
|
||||
|
|
@ -146,6 +148,8 @@ def setSettings():
|
|||
if "timeoutConnection" in data["serial"].keys(): s.setFloat(["serial", "timeout", "connection"], data["serial"]["timeoutConnection"])
|
||||
if "timeoutDetection" in data["serial"].keys(): s.setFloat(["serial", "timeout", "detection"], data["serial"]["timeoutDetection"])
|
||||
if "timeoutCommunication" in data["serial"].keys(): s.setFloat(["serial", "timeout", "communication"], data["serial"]["timeoutCommunication"])
|
||||
if "timeoutTemperature" in data["serial"].keys(): s.setFloat(["serial", "timeout", "temperature"], data["serial"]["timeoutTemperature"])
|
||||
if "timeoutSdStatus" in data["serial"].keys(): s.setFloat(["serial", "timeout", "sdStatus"], data["serial"]["timeoutSdStatus"])
|
||||
|
||||
oldLog = s.getBoolean(["serial", "log"])
|
||||
if "log" in data["serial"].keys(): s.setBoolean(["serial", "log"], data["serial"]["log"])
|
||||
|
|
|
|||
|
|
@ -23,12 +23,13 @@ from octoprint.server.api import api
|
|||
def getTimelapseData():
|
||||
timelapse = octoprint.timelapse.current
|
||||
|
||||
type = "off"
|
||||
config = {"type": "off"}
|
||||
if timelapse is not None and isinstance(timelapse, octoprint.timelapse.ZTimelapse):
|
||||
config["type"] = "zchange"
|
||||
config["postRoll"] = timelapse.postRoll()
|
||||
elif timelapse is not None and isinstance(timelapse, octoprint.timelapse.TimedTimelapse):
|
||||
config["type"] = "timed"
|
||||
config["postRoll"] = timelapse.postRoll()
|
||||
config.update({
|
||||
"interval": timelapse.interval()
|
||||
})
|
||||
|
|
@ -64,9 +65,17 @@ def setTimelapseConfig():
|
|||
if "type" in request.values:
|
||||
config = {
|
||||
"type": request.values["type"],
|
||||
"postRoll": 0,
|
||||
"options": {}
|
||||
}
|
||||
|
||||
|
||||
if "postRoll" in request.values:
|
||||
try:
|
||||
config["postRoll"] = int(request.values["postRoll"])
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if "interval" in request.values:
|
||||
interval = 10
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -31,7 +31,9 @@ default_settings = {
|
|||
"timeout": {
|
||||
"detection": 0.5,
|
||||
"connection": 2,
|
||||
"communication": 5
|
||||
"communication": 5,
|
||||
"temperature": 5,
|
||||
"sdStatus": 1
|
||||
},
|
||||
"additionalPorts": []
|
||||
},
|
||||
|
|
@ -52,7 +54,8 @@ default_settings = {
|
|||
"flipV": False,
|
||||
"timelapse": {
|
||||
"type": "off",
|
||||
"options": {}
|
||||
"options": {},
|
||||
"postRoll": 0
|
||||
}
|
||||
},
|
||||
"gcodeViewer": {
|
||||
|
|
@ -145,7 +148,8 @@ default_settings = {
|
|||
"okWithLinenumber": False,
|
||||
"numExtruders": 1,
|
||||
"includeCurrentToolInTemps": True,
|
||||
"hasBed": True
|
||||
"hasBed": True,
|
||||
"repetierStyleTargetTemperature": False
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -370,14 +370,15 @@ GCODE.renderer = (function(){
|
|||
var applyZoom = function(mdlInfo) {
|
||||
var pt = ctx.transformedPoint(canvas.width/2,canvas.height/2);
|
||||
var transform = ctx.getTransform();
|
||||
var scaleF;
|
||||
if (scaleX && scaleY && transform.a && transform.d) {
|
||||
ctx.translate(pt.x, pt.y);
|
||||
ctx.scale(1 / scaleX, 1 / scaleY);
|
||||
ctx.translate(-pt.x, -pt.y);
|
||||
transform = ctx.getTransform();
|
||||
}
|
||||
|
||||
if (mdlInfo && renderOptions["zoomInOnModel"]) {
|
||||
scaleF = mdlInfo.modelSize.x > mdlInfo.modelSize.y ? (canvas.width - 10) / mdlInfo.modelSize.x : (canvas.height - 10) / mdlInfo.modelSize.y;
|
||||
var scaleF = mdlInfo.modelSize.x > mdlInfo.modelSize.y ? (canvas.width - 10) / mdlInfo.modelSize.x : (canvas.height - 10) / mdlInfo.modelSize.y;
|
||||
scaleF /= zoomFactor;
|
||||
if (transform.a && transform.d) {
|
||||
scaleX = scaleF / transform.a;
|
||||
|
|
@ -409,10 +410,11 @@ GCODE.renderer = (function(){
|
|||
var mustRefresh = false;
|
||||
var dirty = false;
|
||||
for (var opt in options) {
|
||||
if (!options.hasOwnProperty(opt)) continue;
|
||||
if (!renderOptions.hasOwnProperty(opt) || !options.hasOwnProperty(opt)) continue;
|
||||
if (options[opt] === undefined) continue;
|
||||
if (renderOptions[opt] == options[opt]) continue;
|
||||
|
||||
dirty = dirty || (renderOptions[opt] != options[opt]);
|
||||
dirty = true;
|
||||
renderOptions[opt] = options[opt];
|
||||
if ($.inArray(opt, ["moveModel", "centerViewport", "zoomInOnModel", "bed"])) {
|
||||
mustRefresh = true;
|
||||
|
|
|
|||
|
|
@ -106,6 +106,8 @@ function SettingsViewModel(loginStateViewModel, usersViewModel) {
|
|||
self.serial_timeoutConnection = ko.observable(undefined);
|
||||
self.serial_timeoutDetection = ko.observable(undefined);
|
||||
self.serial_timeoutCommunication = ko.observable(undefined);
|
||||
self.serial_timeoutTemperature = ko.observable(undefined);
|
||||
self.serial_timeoutSdStatus = ko.observable(undefined);
|
||||
self.serial_log = ko.observable(undefined);
|
||||
|
||||
self.folder_uploads = ko.observable(undefined);
|
||||
|
|
@ -216,6 +218,8 @@ function SettingsViewModel(loginStateViewModel, usersViewModel) {
|
|||
self.serial_timeoutConnection(response.serial.timeoutConnection);
|
||||
self.serial_timeoutDetection(response.serial.timeoutDetection);
|
||||
self.serial_timeoutCommunication(response.serial.timeoutCommunication);
|
||||
self.serial_timeoutTemperature(response.serial.timeoutTemperature);
|
||||
self.serial_timeoutSdStatus(response.serial.timeoutSdStatus);
|
||||
self.serial_log(response.serial.log);
|
||||
|
||||
self.folder_uploads(response.folder.uploads);
|
||||
|
|
@ -279,6 +283,8 @@ function SettingsViewModel(loginStateViewModel, usersViewModel) {
|
|||
"timeoutConnection": self.serial_timeoutConnection(),
|
||||
"timeoutDetection": self.serial_timeoutDetection(),
|
||||
"timeoutCommunication": self.serial_timeoutCommunication(),
|
||||
"timeoutTemperature": self.serial_timeoutTemperature(),
|
||||
"timeoutSdStatus": self.serial_timeoutSdStatus(),
|
||||
"log": self.serial_log()
|
||||
},
|
||||
"folder": {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ function TimelapseViewModel(loginStateViewModel) {
|
|||
|
||||
self.timelapseType = ko.observable(undefined);
|
||||
self.timelapseTimedInterval = ko.observable(undefined);
|
||||
self.timelapsePostRoll = ko.observable(undefined);
|
||||
|
||||
self.persist = ko.observable(false);
|
||||
self.isDirty = ko.observable(false);
|
||||
|
|
@ -17,6 +18,9 @@ function TimelapseViewModel(loginStateViewModel) {
|
|||
self.isReady = ko.observable(undefined);
|
||||
self.isLoading = ko.observable(undefined);
|
||||
|
||||
self.timelapseTypeSelected = ko.computed(function() {
|
||||
return ("off" != self.timelapseType());
|
||||
});
|
||||
self.intervalInputEnabled = ko.computed(function() {
|
||||
return ("timed" == self.timelapseType());
|
||||
});
|
||||
|
|
@ -122,6 +126,7 @@ function TimelapseViewModel(loginStateViewModel) {
|
|||
self.save = function(data, event) {
|
||||
var data = {
|
||||
"type": self.timelapseType(),
|
||||
"postRoll": self.timelapsePostRoll(),
|
||||
"save": self.persist()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -333,7 +333,8 @@ table {
|
|||
width: 50px;
|
||||
}
|
||||
|
||||
#temp_newTemp, #temp_newBedTemp, #speed_innerWall, #speed_outerWall, #speed_fill, #speed_support, #webcam_timelapse_interval {
|
||||
#temp_newTemp, #temp_newBedTemp, #speed_innerWall, #speed_outerWall, #speed_fill, #speed_support,
|
||||
#webcam_timelapse_interval, #webcam_timelapse_postRoll {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -533,7 +533,13 @@
|
|||
<option value="timed">Timed</option>
|
||||
</select>
|
||||
|
||||
<div id="webcam_timelapse_timedsettings" data-bind="visible: intervalInputEnabled()">
|
||||
<label for="webcam_timelapse_postRoll">Timelapse post roll (in rendered seconds)</label>
|
||||
<div class="input-append">
|
||||
<input type="text" class="input-mini" id="webcam_timelapse_postRoll" data-bind="value: timelapsePostRoll, valueUpdate: 'afterkeydown', enable: isOperational() && !isPrinting() && loginState.isUser() && timelapseTypeSelected()">
|
||||
<span class="add-on">sec</span>
|
||||
</div>
|
||||
|
||||
<div id="webcam_timelapse_timedsettings" data-bind="visible: intervalInputEnabled">
|
||||
<label for="webcam_timelapse_interval">Interval</label>
|
||||
<div class="input-append">
|
||||
<input type="text" class="input-mini" id="webcam_timelapse_interval" data-bind="value: timelapseTimedInterval, valueUpdate: 'afterkeydown', enable: isOperational() && !isPrinting() && loginState.isUser()">
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="settings-movementSpeedE">Communication timeout</label>
|
||||
<label class="control-label" for="settings-serialTimeoutCommunication">Communication timeout</label>
|
||||
<div class="controls">
|
||||
<div class="input-append">
|
||||
<input type="number" step="any" min="0" class="input-mini text-right" data-bind="value: serial_timeoutCommunication" id="settings-serialTimeoutCommunication">
|
||||
|
|
@ -55,7 +55,25 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="settings-movementSpeedE">Connection timeout</label>
|
||||
<label class="control-label" for="settings-movementSpeedE">Temperature timeout</label>
|
||||
<div class="controls">
|
||||
<div class="input-append">
|
||||
<input type="number" step="any" min="0" class="input-mini text-right" data-bind="value: serial_timeoutTemperature" id="settings-serialTimeoutTemperature">
|
||||
<span class="add-on">s</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="settings-serialTimeoutSdStatus">SD status timeout</label>
|
||||
<div class="controls">
|
||||
<div class="input-append">
|
||||
<input type="number" step="any" min="0" class="input-mini text-right" data-bind="value: serial_timeoutSdStatus" id="settings-serialTimeoutSdStatus">
|
||||
<span class="add-on">s</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="settings-serialTimeoutConnection">Connection timeout</label>
|
||||
<div class="controls">
|
||||
<div class="input-append">
|
||||
<input type="number" step="any" min="0" class="input-mini text-right" data-bind="value: serial_timeoutConnection" id="settings-serialTimeoutConnection">
|
||||
|
|
@ -64,7 +82,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="settings-movementSpeedE">Autodetection timeout</label>
|
||||
<label class="control-label" for="settings-serialTimeoutDetection">Autodetection timeout</label>
|
||||
<div class="controls">
|
||||
<div class="input-append">
|
||||
<input type="number" step="any" min="0" class="input-mini text-right" data-bind="value: serial_timeoutDetection" id="settings-serialTimeoutDetection">
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import subprocess
|
|||
import fnmatch
|
||||
import datetime
|
||||
import sys
|
||||
import shutil
|
||||
|
||||
import octoprint.util as util
|
||||
|
||||
|
|
@ -72,15 +73,20 @@ def configureTimelapse(config=None, persist=False):
|
|||
current.unload()
|
||||
|
||||
type = config["type"]
|
||||
|
||||
postRoll = 0
|
||||
if "postRoll" in config:
|
||||
postRoll = config["postRoll"]
|
||||
|
||||
if type is None or "off" == type:
|
||||
current = None
|
||||
elif "zchange" == type:
|
||||
current = ZTimelapse()
|
||||
current = ZTimelapse(postRoll=postRoll)
|
||||
elif "timed" == type:
|
||||
interval = 10
|
||||
if "options" in config and "interval" in config["options"]:
|
||||
interval = config["options"]["interval"]
|
||||
current = TimedTimelapse(interval)
|
||||
current = TimedTimelapse(postRoll=postRoll, interval=interval)
|
||||
|
||||
notifyCallbacks(current)
|
||||
|
||||
|
|
@ -90,16 +96,22 @@ def configureTimelapse(config=None, persist=False):
|
|||
|
||||
|
||||
class Timelapse(object):
|
||||
def __init__(self):
|
||||
def __init__(self, postRoll=0):
|
||||
self._logger = logging.getLogger(__name__)
|
||||
self._imageNumber = None
|
||||
self._inTimelapse = False
|
||||
self._gcodeFile = None
|
||||
|
||||
self._postRoll = postRoll
|
||||
self._postRollStart = None
|
||||
self._onPostRollDone = None
|
||||
|
||||
self._captureDir = settings().getBaseFolder("timelapse_tmp")
|
||||
self._movieDir = settings().getBaseFolder("timelapse")
|
||||
self._snapshotUrl = settings().get(["webcam", "snapshot"])
|
||||
|
||||
self._fps = 25
|
||||
|
||||
self._renderThread = None
|
||||
self._captureMutex = threading.Lock()
|
||||
|
||||
|
|
@ -111,6 +123,9 @@ class Timelapse(object):
|
|||
for (event, callback) in self.eventSubscriptions():
|
||||
eventManager().subscribe(event, callback)
|
||||
|
||||
def postRoll(self):
|
||||
return self._postRoll
|
||||
|
||||
def unload(self):
|
||||
if self._inTimelapse:
|
||||
self.stopTimelapse(doCreateMovie=False)
|
||||
|
|
@ -175,13 +190,36 @@ class Timelapse(object):
|
|||
def stopTimelapse(self, doCreateMovie=True, success=True):
|
||||
self._logger.debug("Stopping timelapse")
|
||||
|
||||
if doCreateMovie:
|
||||
self._inTimelapse = False
|
||||
|
||||
def resetImageNumber():
|
||||
self._imageNumber = None
|
||||
|
||||
def createMovie():
|
||||
self._renderThread = threading.Thread(target=self._createMovie, kwargs={"success": success})
|
||||
self._renderThread.daemon = True
|
||||
self._renderThread.start()
|
||||
|
||||
self._imageNumber = None
|
||||
self._inTimelapse = False
|
||||
def resetAndCreate():
|
||||
resetImageNumber()
|
||||
createMovie()
|
||||
|
||||
if self._postRoll > 0:
|
||||
self._postRollStart = time.time()
|
||||
if doCreateMovie:
|
||||
self._onPostRollDone = resetAndCreate
|
||||
else:
|
||||
self._onPostRollDone = resetImageNumber
|
||||
self.processPostRoll()
|
||||
else:
|
||||
self._postRollStart = None
|
||||
if doCreateMovie:
|
||||
resetAndCreate()
|
||||
else:
|
||||
resetImageNumber()
|
||||
|
||||
def processPostRoll(self):
|
||||
pass
|
||||
|
||||
def captureImage(self):
|
||||
if self._captureDir is None:
|
||||
|
|
@ -195,6 +233,7 @@ class Timelapse(object):
|
|||
captureThread = threading.Thread(target=self._captureWorker, kwargs={"filename": filename})
|
||||
captureThread.daemon = True
|
||||
captureThread.start()
|
||||
return filename
|
||||
|
||||
def _captureWorker(self, filename):
|
||||
eventManager().fire(Events.CAPTURE_START, {"file": filename});
|
||||
|
|
@ -217,7 +256,7 @@ class Timelapse(object):
|
|||
|
||||
# prepare ffmpeg command
|
||||
command = [
|
||||
ffmpeg, '-i', input, '-vcodec', 'mpeg2video', '-pix_fmt', 'yuv420p', '-r', '25', '-y', '-b:v', bitrate,
|
||||
ffmpeg, '-i', input, '-vcodec', 'mpeg2video', '-pix_fmt', 'yuv420p', '-r', str(self._fps), '-y', '-b:v', bitrate,
|
||||
'-f', 'vob']
|
||||
|
||||
filters = []
|
||||
|
|
@ -275,8 +314,8 @@ class Timelapse(object):
|
|||
|
||||
|
||||
class ZTimelapse(Timelapse):
|
||||
def __init__(self):
|
||||
Timelapse.__init__(self)
|
||||
def __init__(self, postRoll=0):
|
||||
Timelapse.__init__(self, postRoll=postRoll)
|
||||
self._logger.debug("ZTimelapse initialized")
|
||||
|
||||
def eventSubscriptions(self):
|
||||
|
|
@ -289,13 +328,29 @@ class ZTimelapse(Timelapse):
|
|||
"type": "zchange"
|
||||
}
|
||||
|
||||
def processPostRoll(self):
|
||||
Timelapse.processPostRoll(self)
|
||||
|
||||
filename = os.path.join(self._captureDir, "tmp_%05d.jpg" % self._imageNumber)
|
||||
self._imageNumber += 1
|
||||
with self._captureMutex:
|
||||
self._captureWorker(filename)
|
||||
|
||||
for i in range(self._postRoll * self._fps):
|
||||
newFile = os.path.join(self._captureDir, "tmp_%05d.jpg" % (self._imageNumber))
|
||||
self._imageNumber += 1
|
||||
shutil.copyfile(filename, newFile)
|
||||
|
||||
if self._onPostRollDone is not None:
|
||||
self._onPostRollDone()
|
||||
|
||||
def _onZChange(self, event, payload):
|
||||
self.captureImage()
|
||||
|
||||
|
||||
class TimedTimelapse(Timelapse):
|
||||
def __init__(self, interval=1):
|
||||
Timelapse.__init__(self)
|
||||
def __init__(self, postRoll=0, interval=1):
|
||||
Timelapse.__init__(self, postRoll=postRoll)
|
||||
self._interval = interval
|
||||
if self._interval < 1:
|
||||
self._interval = 1 # force minimum interval of 1s
|
||||
|
|
@ -328,6 +383,10 @@ class TimedTimelapse(Timelapse):
|
|||
|
||||
def _timerWorker(self):
|
||||
self._logger.debug("Starting timer for interval based timelapse")
|
||||
while self._inTimelapse:
|
||||
while self._inTimelapse or (self._postRollStart and time.time() - self._postRollStart <= self._postRoll * self._fps):
|
||||
self.captureImage()
|
||||
time.sleep(self._interval)
|
||||
|
||||
if self._postRollStart is not None and self._onPostRollDone is not None:
|
||||
self._onPostRollDone()
|
||||
self._postRollStart = None
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import re
|
|||
import tempfile
|
||||
from flask import make_response
|
||||
|
||||
from octoprint.settings import settings
|
||||
from octoprint.settings import settings, default_settings
|
||||
|
||||
|
||||
def getFormattedSize(num):
|
||||
|
|
@ -89,8 +89,9 @@ def getGitInfo():
|
|||
def getNewTimeout(type):
|
||||
now = time.time()
|
||||
|
||||
if type not in ["connection", "detection", "communication"]:
|
||||
return now # timeout immediately for unknown timeout type
|
||||
if type not in default_settings["serial"]["timeout"].keys():
|
||||
# timeout immediately for unknown timeout type
|
||||
return now
|
||||
|
||||
return now + settings().getFloat(["serial", "timeout", type])
|
||||
|
||||
|
|
|
|||
|
|
@ -569,7 +569,14 @@ class MachineCom(object):
|
|||
if not "T0" in parsedTemps.keys() and "T" in parsedTemps.keys():
|
||||
# only single reporting, "T" is our one and only extruder temperature
|
||||
toolNum, actual, target = parsedTemps["T"]
|
||||
self._temp[0] = (actual, target)
|
||||
|
||||
if target is not None:
|
||||
self._temp[0] = (actual, target)
|
||||
elif 0 in self._temp.keys() and self._temp[0] is not None and isinstance(self._temp[0], tuple):
|
||||
(oldActual, oldTarget) = self._temp[0]
|
||||
self._temp[0] = (actual, oldTarget)
|
||||
else:
|
||||
self._temp[0] = (actual, None)
|
||||
elif "T0" in parsedTemps.keys():
|
||||
for n in range(maxToolNum + 1):
|
||||
tool = "T%d" % n
|
||||
|
|
@ -614,8 +621,8 @@ class MachineCom(object):
|
|||
|
||||
#Start monitoring the serial port.
|
||||
timeout = getNewTimeout("communication")
|
||||
tempRequestTimeout = timeout
|
||||
sdStatusRequestTimeout = timeout
|
||||
tempRequestTimeout = getNewTimeout("temperature")
|
||||
sdStatusRequestTimeout = getNewTimeout("sdStatus")
|
||||
startSeen = not settings().getBoolean(["feature", "waitForStartOnConnect"])
|
||||
heatingUp = False
|
||||
swallowOk = False
|
||||
|
|
@ -626,6 +633,8 @@ class MachineCom(object):
|
|||
line = self._readline()
|
||||
if line is None:
|
||||
break
|
||||
if line.strip() is not "":
|
||||
timeout = getNewTimeout("communication")
|
||||
|
||||
##~~ Error handling
|
||||
line = self._handleErrors(line)
|
||||
|
|
@ -702,7 +711,7 @@ class MachineCom(object):
|
|||
self._callback.mcSdFiles(self._sdFiles)
|
||||
elif 'SD printing byte' in line:
|
||||
# answer to M27, at least on Marlin, Repetier and Sprinter: "SD printing byte %d/%d"
|
||||
match = self._regex_sdPrintingByte.search("([0-9]*)/([0-9]*)", line)
|
||||
match = self._regex_sdPrintingByte.search(line)
|
||||
self._currentFile.setFilepos(int(match.group(1)))
|
||||
self._callback.mcProgress()
|
||||
elif 'File opened' in line:
|
||||
|
|
@ -845,7 +854,7 @@ class MachineCom(object):
|
|||
self._sendCommand(self._commandQueue.get())
|
||||
else:
|
||||
self._sendCommand("M105")
|
||||
tempRequestTimeout = getNewTimeout("communication")
|
||||
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"]):
|
||||
|
|
@ -861,24 +870,20 @@ class MachineCom(object):
|
|||
if self.isSdPrinting():
|
||||
if time.time() > tempRequestTimeout and not heatingUp:
|
||||
self._sendCommand("M105")
|
||||
tempRequestTimeout = getNewTimeout("communication")
|
||||
tempRequestTimeout = getNewTimeout("temperature")
|
||||
|
||||
if time.time() > sdStatusRequestTimeout and not heatingUp:
|
||||
self._sendCommand("M27")
|
||||
sdStatusRequestTimeout = time.time() + 1
|
||||
|
||||
if 'ok' or 'SD printing byte' in line:
|
||||
timeout = getNewTimeout("communication")
|
||||
sdStatusRequestTimeout = getNewTimeout("sdStatus")
|
||||
else:
|
||||
# Even when printing request the temperature every 5 seconds.
|
||||
if time.time() > tempRequestTimeout and not self.isStreaming():
|
||||
self._commandQueue.put("M105")
|
||||
tempRequestTimeout = getNewTimeout("communication")
|
||||
tempRequestTimeout = getNewTimeout("temperature")
|
||||
|
||||
if "ok" in line and swallowOk:
|
||||
swallowOk = False
|
||||
elif "ok" in line:
|
||||
timeout = getNewTimeout("communication")
|
||||
if self._resendDelta is not None:
|
||||
self._resendNextCommand()
|
||||
elif not self._commandQueue.empty() and not self.isStreaming():
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ class VirtualPrinter():
|
|||
linenumber = int(re.search("N([0-9]+)", data).group(1))
|
||||
self.lastN = linenumber
|
||||
self.currentLine = linenumber
|
||||
self._sendOk()
|
||||
return
|
||||
elif data.startswith("N"):
|
||||
linenumber = int(re.search("N([0-9]+)", data).group(1))
|
||||
|
|
@ -91,29 +92,15 @@ class VirtualPrinter():
|
|||
|
||||
#print "Send: %s" % (data.rstrip())
|
||||
if 'M104' in data or 'M109' in data:
|
||||
if not self._parseHotendCommand(data):
|
||||
return
|
||||
self._parseHotendCommand(data)
|
||||
return
|
||||
|
||||
if 'M140' in data or 'M190' in data:
|
||||
if not self._parseBedCommand(data):
|
||||
return
|
||||
self._parseBedCommand(data)
|
||||
return
|
||||
|
||||
if 'M105' in data:
|
||||
# send simulated temperature data
|
||||
if settings().getInt(["devel", "virtualPrinter", "numExtruders"]) > 1:
|
||||
allTemps = []
|
||||
for i in range(len(self.temp)):
|
||||
allTemps.append((i, self.temp[i], self.targetTemp[i]))
|
||||
allTempsString = " ".join(map(lambda x: "T%d:%.2f /%.2f" % x, allTemps))
|
||||
|
||||
if settings().getBoolean(["devel", "virtualPrinter", "hasBed"]):
|
||||
allTempsString = "B:%.2f /%.2f %s" % (self.bedTemp, self.bedTargetTemp, allTempsString)
|
||||
|
||||
if settings().getBoolean(["devel", "virtualPrinter", "includeCurrentToolInTemps"]):
|
||||
self.readList.append("ok T:%.2f /%.2f %s @:64\n" % (self.temp[self.currentExtruder], self.targetTemp[self.currentExtruder] + 1))
|
||||
else:
|
||||
self.readList.append("ok %s @:64\n" % allTempsString)
|
||||
else:
|
||||
self.readList.append("ok T:%.2f /%.2f B:%.2f /%.2f @:64\n" % (self.temp[0], self.targetTemp[0], self.bedTemp, self.bedTargetTemp))
|
||||
self._processTemperatureQuery()
|
||||
elif 'M20' in data:
|
||||
if self._sdCardReady:
|
||||
self._listSd()
|
||||
|
|
@ -204,6 +191,35 @@ class VirtualPrinter():
|
|||
else:
|
||||
self.readList.append("Not SD printing")
|
||||
|
||||
def _processTemperatureQuery(self):
|
||||
includeTarget = not settings().getBoolean(["devel", "virtualPrinter", "repetierStyleTargetTemperature"])
|
||||
|
||||
# send simulated temperature data
|
||||
if settings().getInt(["devel", "virtualPrinter", "numExtruders"]) > 1:
|
||||
allTemps = []
|
||||
for i in range(len(self.temp)):
|
||||
allTemps.append((i, self.temp[i], self.targetTemp[i]))
|
||||
allTempsString = " ".join(map(lambda x: "T%d:%.2f /%.2f" % x if includeTarget else "T%d:%.2f" % (x[0], x[1]), allTemps))
|
||||
|
||||
if settings().getBoolean(["devel", "virtualPrinter", "hasBed"]):
|
||||
if includeTarget:
|
||||
allTempsString = "B:%.2f /%.2f %s" % (self.bedTemp, self.bedTargetTemp, allTempsString)
|
||||
else:
|
||||
allTempsString = "B:%.2f %s" % (self.bedTemp, allTempsString)
|
||||
|
||||
if settings().getBoolean(["devel", "virtualPrinter", "includeCurrentToolInTemps"]):
|
||||
if includeTarget:
|
||||
self.readList.append("ok T:%.2f /%.2f %s @:64\n" % (self.temp[self.currentExtruder], self.targetTemp[self.currentExtruder] + 1, allTempsString))
|
||||
else:
|
||||
self.readList.append("ok T:%.2f %s @:64\n" % (self.temp[self.currentExtruder], allTempsString))
|
||||
else:
|
||||
self.readList.append("ok %s @:64\n" % allTempsString)
|
||||
else:
|
||||
if includeTarget:
|
||||
self.readList.append("ok T:%.2f /%.2f B:%.2f /%.2f @:64\n" % (self.temp[0], self.targetTemp[0], self.bedTemp, self.bedTargetTemp))
|
||||
else:
|
||||
self.readList.append("ok T:%.2f B:%.2f @:64\n" % (self.temp[0], self.bedTemp))
|
||||
|
||||
def _parseHotendCommand(self, line):
|
||||
tool = 0
|
||||
toolMatch = re.search('T([0-9]+)', line)
|
||||
|
|
@ -214,6 +230,7 @@ class VirtualPrinter():
|
|||
pass
|
||||
|
||||
if tool >= settings().getInt(["devel", "virtualPrinter", "numExtruders"]):
|
||||
self._sendOk()
|
||||
return
|
||||
|
||||
try:
|
||||
|
|
@ -224,8 +241,12 @@ class VirtualPrinter():
|
|||
if "M109" in line:
|
||||
self._heatupThread = threading.Thread(target=self._waitForHeatup, args=["tool%d" % tool])
|
||||
self._heatupThread.start()
|
||||
return False
|
||||
return True
|
||||
return
|
||||
|
||||
self._sendOk()
|
||||
|
||||
if settings().getBoolean(["devel", "virtualPrinter", "repetierStyleTargetTemperature"]):
|
||||
self.readList.append("TargetExtr%d:%d" % (tool, self.targetTemp[tool]))
|
||||
|
||||
def _parseBedCommand(self, line):
|
||||
try:
|
||||
|
|
@ -236,8 +257,12 @@ class VirtualPrinter():
|
|||
if "M190" in line:
|
||||
self._heatupThread = threading.Thread(target=self._waitForHeatup, args=["bed"])
|
||||
self._heatupThread.start()
|
||||
return False
|
||||
return True
|
||||
return
|
||||
|
||||
self._sendOk()
|
||||
|
||||
if settings().getBoolean(["devel", "virtualPrinter", "repetierStyleTargetTemperature"]):
|
||||
self.readList.append("TargetBed:%d" % self.bedTargetTemp)
|
||||
|
||||
def _writeSdFile(self, filename):
|
||||
file = os.path.join(self._virtualSd, filename).lower()
|
||||
|
|
@ -260,7 +285,7 @@ class VirtualPrinter():
|
|||
def _sdPrintingWorker(self):
|
||||
self._selectedSdFilePos = 0
|
||||
with open(self._selectedSdFile, "r") as f:
|
||||
for line in f:
|
||||
for line in iter(f.readline, ""):
|
||||
# reset position if requested by client
|
||||
if self._newSdFilePos is not None:
|
||||
f.seek(self._newSdFilePos)
|
||||
|
|
|
|||
Loading…
Reference in a new issue