Added option to disable analysis of gcode upon loading a file for print. Disabling this allows for a faster loading time (especially on a Raspberry Pi) but with the disadvantage of losing information regarding estimated filament length and print time.
parent
c2858200eb
commit
574961ceac
41
README.md
41
README.md
|
@ -5,7 +5,8 @@ The Printer WebUI provides a responsive web interface for controlling a 3D print
|
||||||
allows
|
allows
|
||||||
|
|
||||||
* uploading .gcode files to the server and managing them via the UI
|
* uploading .gcode files to the server and managing them via the UI
|
||||||
* selecting a file for printing, getting the usual stats regarding filament length etc
|
* selecting a file for printing, getting the usual stats regarding filament length etc (stats can be disabled for
|
||||||
|
faster initial processing)
|
||||||
* starting, pausing and canceling a print job
|
* starting, pausing and canceling a print job
|
||||||
* while connected to the printer, gaining information regarding the current temperature of both head and bed (if available) in a nice shiny javascript-y temperature graph
|
* while connected to the printer, gaining information regarding the current temperature of both head and bed (if available) in a nice shiny javascript-y temperature graph
|
||||||
* while printing, gaining information regarding the current progress of the print job (height, percentage etc)
|
* while printing, gaining information regarding the current progress of the print job (height, percentage etc)
|
||||||
|
@ -49,40 +50,54 @@ Alternatively, the host and port on which to bind can be defined via the configu
|
||||||
Configuration
|
Configuration
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
The config-file `config.ini` for Printer WebUI is expected at `~/.printerwebui` for Linux, at `%APPDATA%/PrinterWebUI`
|
The config-file `config.ini` for Printer WebUI is expected in its settings folder, which is located at `~/.printerwebui`
|
||||||
for Windows and at `~/Library/Application Support` for MacOS X.
|
on Linux, at `%APPDATA%/PrinterWebUI` on Windows and at `~/Library/Application Support` on MacOS X.
|
||||||
|
|
||||||
The following example config should explain the available options:
|
The following example config should explain the available options:
|
||||||
|
|
||||||
[serial]
|
[serial]
|
||||||
# use the following option to define the default serial port, defaults to unset (= AUTO)
|
# Use the following option to define the default serial port, defaults to unset (= AUTO)
|
||||||
port = /dev/ttyACM0
|
port = /dev/ttyACM0
|
||||||
# use the following option to define the default baudrate, defaults to unset (= AUTO)
|
|
||||||
|
# Use the following option to define the default baudrate, defaults to unset (= AUTO)
|
||||||
baudrate = 115200
|
baudrate = 115200
|
||||||
|
|
||||||
[server]
|
[server]
|
||||||
# use this option to define the host to which to bind the server, defaults to "0.0.0.0" (= all interfaces)
|
# Use this option to define the host to which to bind the server, defaults to "0.0.0.0" (= all interfaces)
|
||||||
host = 0.0.0.0
|
host = 0.0.0.0
|
||||||
# use this option to define the port to which to bind the server, defaults to 5000
|
|
||||||
|
# Use this option to define the port to which to bind the server, defaults to 5000
|
||||||
port = 5000
|
port = 5000
|
||||||
|
|
||||||
[webcam]
|
[webcam]
|
||||||
# use this option to enable display of a webcam stream in the UI, e.g. via MJPG-Streamer.
|
# Use this option to enable display of a webcam stream in the UI, e.g. via MJPG-Streamer.
|
||||||
# Webcam support will be disabled if not set
|
# Webcam support will be disabled if not set
|
||||||
stream = http://<stream host>:<stream port>/?action=stream
|
stream = http://<stream host>:<stream port>/?action=stream
|
||||||
# use this option to enable timelapse support via snapshot, e.g. via MJPG-Streamer.
|
|
||||||
|
# Use this option to enable timelapse support via snapshot, e.g. via MJPG-Streamer.
|
||||||
# Timelapse support will be disabled if not set
|
# Timelapse support will be disabled if not set
|
||||||
snapshot = http://<stream host>:<stream port>/?action=snapshot
|
snapshot = http://<stream host>:<stream port>/?action=snapshot
|
||||||
# path to ffmpeg binary to use for creating timelapse recordings.
|
|
||||||
|
# Path to ffmpeg binary to use for creating timelapse recordings.
|
||||||
# Timelapse support will be disabled if not set
|
# Timelapse support will be disabled if not set
|
||||||
ffmpeg = /path/to/ffmpeg
|
ffmpeg = /path/to/ffmpeg
|
||||||
|
|
||||||
|
[feature]
|
||||||
|
# Whether to enable gcode analysis for displaying needed filament and estimated print time. Disabling this (set
|
||||||
|
# to False) will speed up the loading of gcode files before printing significantly, but the mentioned statistical
|
||||||
|
# data will not be available
|
||||||
|
analyzeGcode = True
|
||||||
|
|
||||||
[folder]
|
[folder]
|
||||||
# absolute path where to store gcode uploads. Defaults to the uploads folder in the Printer WebUI settings dir
|
# Absolute path where to store gcode uploads. Defaults to the uploads folder in the Printer WebUI settings folder
|
||||||
uploads = /path/to/upload/folder
|
uploads = /path/to/upload/folder
|
||||||
# absolute path where to store finished timelapse recordings. Defaults to the timelapse folder in the Printer WebUI settings dir
|
|
||||||
|
# Absolute path where to store finished timelapse recordings. Defaults to the timelapse folder in the Printer WebUI
|
||||||
|
# settings dir
|
||||||
timelapse = /path/to/timelapse/folder
|
timelapse = /path/to/timelapse/folder
|
||||||
# absolute path where to store temporary timelapse files. Defaults to the timelapse/tmp folder in the Printer WebUI settings dir
|
|
||||||
|
# Absolute path where to store temporary timelapse files. Defaults to the timelapse/tmp folder in the Printer WebUI
|
||||||
|
# settings dir
|
||||||
timelapse_tmp = /path/timelapse/tmp/folder
|
timelapse_tmp = /path/timelapse/tmp/folder
|
||||||
|
|
||||||
Setup on a Raspberry Pi running Raspbian
|
Setup on a Raspberry Pi running Raspbian
|
||||||
|
|
|
@ -295,6 +295,9 @@ class Printer():
|
||||||
formattedPrintTimeEstimation = _getFormattedTimeDelta(datetime.timedelta(minutes=self._gcode.totalMoveTimeMinute))
|
formattedPrintTimeEstimation = _getFormattedTimeDelta(datetime.timedelta(minutes=self._gcode.totalMoveTimeMinute))
|
||||||
if self._gcode.extrusionAmount:
|
if self._gcode.extrusionAmount:
|
||||||
formattedFilament = "%.2fm" % (self._gcode.extrusionAmount / 1000)
|
formattedFilament = "%.2fm" % (self._gcode.extrusionAmount / 1000)
|
||||||
|
elif not settings().getBoolean("feature", "analyzeGcode"):
|
||||||
|
formattedPrintTimeEstimation = "unknown"
|
||||||
|
formattedFilament = "unknown"
|
||||||
|
|
||||||
formattedFilename = None
|
formattedFilename = None
|
||||||
if self._filename:
|
if self._filename:
|
||||||
|
@ -385,12 +388,12 @@ class Printer():
|
||||||
|
|
||||||
#~~ callbacks triggered by gcodeLoader
|
#~~ callbacks triggered by gcodeLoader
|
||||||
|
|
||||||
def _onGcodeLoadingProgress(self, filename, progress):
|
def _onGcodeLoadingProgress(self, filename, progress, mode):
|
||||||
formattedFilename = None
|
formattedFilename = None
|
||||||
if filename is not None:
|
if filename is not None:
|
||||||
formattedFilename = os.path.basename(filename)
|
formattedFilename = os.path.basename(filename)
|
||||||
|
|
||||||
self._stateMonitor.setGcodeData({"filename": formattedFilename, "progress": progress})
|
self._stateMonitor.setGcodeData({"filename": formattedFilename, "progress": progress, "mode": mode})
|
||||||
|
|
||||||
def _onGcodeLoaded(self, filename, gcode, gcodeList):
|
def _onGcodeLoaded(self, filename, gcode, gcodeList):
|
||||||
formattedFilename = None
|
formattedFilename = None
|
||||||
|
@ -464,8 +467,6 @@ class GcodeLoader(threading.Thread):
|
||||||
self._loadedCallback = loadedCallback
|
self._loadedCallback = loadedCallback
|
||||||
|
|
||||||
self._filename = filename
|
self._filename = filename
|
||||||
self._progress = None
|
|
||||||
|
|
||||||
self._gcode = None
|
self._gcode = None
|
||||||
self._gcodeList = None
|
self._gcodeList = None
|
||||||
|
|
||||||
|
@ -473,6 +474,7 @@ class GcodeLoader(threading.Thread):
|
||||||
#Send an initial M110 to reset the line counter to zero.
|
#Send an initial M110 to reset the line counter to zero.
|
||||||
prevLineType = lineType = "CUSTOM"
|
prevLineType = lineType = "CUSTOM"
|
||||||
gcodeList = ["M110"]
|
gcodeList = ["M110"]
|
||||||
|
filesize = os.stat(self._filename).st_size
|
||||||
with open(self._filename, "r") as file:
|
with open(self._filename, "r") as file:
|
||||||
for line in file:
|
for line in file:
|
||||||
if line.startswith(";TYPE:"):
|
if line.startswith(";TYPE:"):
|
||||||
|
@ -486,17 +488,21 @@ class GcodeLoader(threading.Thread):
|
||||||
else:
|
else:
|
||||||
gcodeList.append(line)
|
gcodeList.append(line)
|
||||||
prevLineType = lineType
|
prevLineType = lineType
|
||||||
|
self._onLoadingProgress(float(file.tell()) / float(filesize))
|
||||||
|
|
||||||
self._gcodeList = gcodeList
|
self._gcodeList = gcodeList
|
||||||
self._gcode = gcodeInterpreter.gcode()
|
if settings().getBoolean("feature", "analyzeGcode"):
|
||||||
self._gcode.progressCallback = self.onProgress
|
self._gcode = gcodeInterpreter.gcode()
|
||||||
self._gcode.loadList(self._gcodeList)
|
self._gcode.progressCallback = self._onParsingProgress
|
||||||
|
self._gcode.loadList(self._gcodeList)
|
||||||
|
|
||||||
self._loadedCallback(self._filename, self._gcode, self._gcodeList)
|
self._loadedCallback(self._filename, self._gcode, self._gcodeList)
|
||||||
|
|
||||||
def onProgress(self, progress):
|
def _onLoadingProgress(self, progress):
|
||||||
self._progress = progress
|
self._progressCallback(self._filename, progress, "loading")
|
||||||
self._progressCallback(self._filename, self._progress)
|
|
||||||
|
def _onParsingProgress(self, progress):
|
||||||
|
self._progressCallback(self._filename, progress, "parsing")
|
||||||
|
|
||||||
class PrinterCallback(object):
|
class PrinterCallback(object):
|
||||||
def sendCurrentData(self, data):
|
def sendCurrentData(self, data):
|
||||||
|
|
|
@ -27,7 +27,8 @@ def index():
|
||||||
return render_template(
|
return render_template(
|
||||||
"index.html",
|
"index.html",
|
||||||
webcamStream=settings().get("webcam", "stream"),
|
webcamStream=settings().get("webcam", "stream"),
|
||||||
enableTimelapse=(settings().get("webcam", "snapshot") is not None and settings().get("webcam", "ffmpeg") is not None)
|
enableTimelapse=(settings().get("webcam", "snapshot") is not None and settings().get("webcam", "ffmpeg") is not None),
|
||||||
|
enableEstimations=(settings().getBoolean("feature", "analyzeGcode"))
|
||||||
)
|
)
|
||||||
|
|
||||||
#~~ Printer state
|
#~~ Printer state
|
||||||
|
|
|
@ -34,6 +34,9 @@ default_settings = {
|
||||||
"uploads": None,
|
"uploads": None,
|
||||||
"timelapse": None,
|
"timelapse": None,
|
||||||
"timelapse_tmp": None
|
"timelapse_tmp": None
|
||||||
|
},
|
||||||
|
"feature": {
|
||||||
|
"analyzeGcode": True
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,16 +90,13 @@ class Settings(object):
|
||||||
if section not in default_settings.keys():
|
if section not in default_settings.keys():
|
||||||
return None
|
return None
|
||||||
|
|
||||||
value = None
|
|
||||||
if self._config.has_option(section, key):
|
if self._config.has_option(section, key):
|
||||||
value = self._config.get(section, key)
|
return self._config.get(section, key)
|
||||||
if value is None:
|
|
||||||
if default_settings.has_key(section) and default_settings[section].has_key(key):
|
if default_settings.has_key(section) and default_settings[section].has_key(key):
|
||||||
return default_settings[section][key]
|
return default_settings[section][key]
|
||||||
else:
|
|
||||||
return None
|
return None
|
||||||
else:
|
|
||||||
return value
|
|
||||||
|
|
||||||
def getInt(self, section, key):
|
def getInt(self, section, key):
|
||||||
value = self.get(section, key)
|
value = self.get(section, key)
|
||||||
|
@ -108,6 +108,14 @@ class Settings(object):
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def getBoolean(self, section, key):
|
||||||
|
value = self.get(section, key)
|
||||||
|
if value is None:
|
||||||
|
return None
|
||||||
|
if isinstance(value, bool):
|
||||||
|
return value
|
||||||
|
return value.lower() in ["true", "yes", "y", "1"]
|
||||||
|
|
||||||
def getBaseFolder(self, type):
|
def getBaseFolder(self, type):
|
||||||
if type not in default_settings["folder"].keys():
|
if type not in default_settings["folder"].keys():
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -182,7 +182,12 @@ function PrinterStateViewModel() {
|
||||||
|
|
||||||
self._processGcodeData = function(data) {
|
self._processGcodeData = function(data) {
|
||||||
if (self.isLoading()) {
|
if (self.isLoading()) {
|
||||||
self.filename("Loading... (" + Math.round(data.progress * 100) + "%)");
|
var progress = Math.round(data.progress * 100);
|
||||||
|
if (data.mode == "loading") {
|
||||||
|
self.filename("Loading... (" + progress + "%)");
|
||||||
|
} else if (data.mode == "parsing") {
|
||||||
|
self.filename("Parsing... (" + progress + "%)");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,8 +52,10 @@
|
||||||
<div class="accordion-inner">
|
<div class="accordion-inner">
|
||||||
Machine State: <strong data-bind="text: stateString"></strong><br>
|
Machine State: <strong data-bind="text: stateString"></strong><br>
|
||||||
File: <strong data-bind="text: filename"></strong><br>
|
File: <strong data-bind="text: filename"></strong><br>
|
||||||
Filament: <strong data-bind="text: filament"></strong><br>
|
{% if enableEstimations %}
|
||||||
Estimated Print Time: <strong data-bind="text: estimatedPrintTime"></strong><br>
|
Filament: <strong data-bind="text: filament"></strong><br>
|
||||||
|
Estimated Print Time: <strong data-bind="text: estimatedPrintTime"></strong><br>
|
||||||
|
{% endif %}
|
||||||
Line: <strong data-bind="text: lineString"></strong><br>
|
Line: <strong data-bind="text: lineString"></strong><br>
|
||||||
Height: <strong data-bind="text: currentHeight"></strong><br>
|
Height: <strong data-bind="text: currentHeight"></strong><br>
|
||||||
Print Time: <strong data-bind="text: printTime"></strong><br>
|
Print Time: <strong data-bind="text: printTime"></strong><br>
|
||||||
|
|
Loading…
Reference in New Issue