parent
8c038a6829
commit
ee7a1f9615
119
README.md
119
README.md
|
@ -12,7 +12,6 @@ allows
|
||||||
* 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)
|
||||||
* reading the communication log and send arbitrary codes to be executed by the printer
|
* reading the communication log and send arbitrary codes to be executed by the printer
|
||||||
* moving the X, Y and Z axis (jog controls, although very ugly ones right now)
|
* moving the X, Y and Z axis (jog controls, although very ugly ones right now)
|
||||||
* changing the speed modifiers for inner & outer wall, fill and support
|
|
||||||
* optional: visual monitoring of the printer via webcam stream integrated into the UI (using e.g. MJPG-Streamer)
|
* optional: visual monitoring of the printer via webcam stream integrated into the UI (using e.g. MJPG-Streamer)
|
||||||
* optional: creation of timelapse recordings of the printjob via webcam stream (using e.g. MJPG-Streamer) -- currently two timelaspe methods are implemented, triggering a shot on z-layer change or every "n" seconds
|
* optional: creation of timelapse recordings of the printjob via webcam stream (using e.g. MJPG-Streamer) -- currently two timelaspe methods are implemented, triggering a shot on z-layer change or every "n" seconds
|
||||||
|
|
||||||
|
@ -66,50 +65,81 @@ on Linux, at `%APPDATA%/OctoPrint` on Windows and at `~/Library/Application Supp
|
||||||
|
|
||||||
The following example config should explain the available options:
|
The following example config should explain the available options:
|
||||||
|
|
||||||
[serial]
|
# Use the following settings to configure the serial connection to the printer
|
||||||
# Use the following option to define the default serial port, defaults to unset (= AUTO)
|
serial:
|
||||||
port = /dev/ttyACM0
|
# Use the following option to define the default serial port, defaults to unset (= AUTO)
|
||||||
|
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]
|
# Use the following settings to configure the web server
|
||||||
# Use this option to define the host to which to bind the server, defaults to "0.0.0.0" (= all interfaces)
|
server:
|
||||||
host = 0.0.0.0
|
# 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
|
||||||
|
|
||||||
# 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]
|
# Use the following settings to configure webcam support
|
||||||
# Use this option to enable display of a webcam stream in the UI, e.g. via MJPG-Streamer.
|
webcam:
|
||||||
# Webcam support will be disabled if not set
|
# Use this option to enable display of a webcam stream in the UI, e.g. via MJPG-Streamer.
|
||||||
stream = http://<stream host>:<stream port>/?action=stream
|
# Webcam support will be disabled if not set
|
||||||
|
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]
|
# Use the following settings to enable or disable OctoPrint features
|
||||||
# Whether to enable gcode analysis for displaying needed filament and estimated print time. Disabling this (set
|
feature:
|
||||||
# to False) will speed up the loading of gcode files before printing significantly, but the mentioned statistical
|
# Whether to enable gcode analysis for displaying needed filament and estimated print time. Disabling this (set
|
||||||
# data will not be available
|
# to false) will speed up the loading of gcode files before printing significantly, but the mentioned statistical
|
||||||
analyzeGcode = True
|
# data will not be available
|
||||||
|
analyzeGcode: true
|
||||||
|
|
||||||
[folder]
|
# Use the following settings to set custom paths for folders used by OctoPrint
|
||||||
# Absolute path where to store gcode uploads. Defaults to the uploads folder in the OctoPrint settings folder
|
folder:
|
||||||
uploads = /path/to/upload/folder
|
# Absolute path where to store gcode uploads. Defaults to the uploads folder in the OctoPrint settings folder
|
||||||
|
uploads: /path/to/upload/folder
|
||||||
|
|
||||||
# Absolute path where to store finished timelapse recordings. Defaults to the timelapse folder in the OctoPrint
|
# Absolute path where to store finished timelapse recordings. Defaults to the timelapse folder in the OctoPrint
|
||||||
# settings dir
|
# 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 OctoPrint
|
||||||
|
# settings dir
|
||||||
|
timelapse_tmp: /path/timelapse/tmp/folder
|
||||||
|
|
||||||
|
# Use the following settings to add custom controls to the "Controls" tab within OctoPrint
|
||||||
|
#
|
||||||
|
# Controls consist at least of a name, a type and type-specific further attributes. Currently recognized types are
|
||||||
|
# - section: Creates a visual section in the UI, you can use this to separate functional blocks
|
||||||
|
# - command: Creates a button that sends a defined GCODE command to the printer when clicked
|
||||||
|
# - parametrized_command: Creates a button that sends a parametrized GCODE command to the printer, parameters
|
||||||
|
# needed for the command are added to the UI as input fields and are named
|
||||||
|
#
|
||||||
|
# The following example defines a control for enabling the cooling fan with a variable speed defined by the user
|
||||||
|
# (default 255) and a control for disabling the fan, all within a section named "Fan".
|
||||||
|
controls:
|
||||||
|
- name: Fan
|
||||||
|
type: section
|
||||||
|
children:
|
||||||
|
- name: Enable Fan
|
||||||
|
type: parametrized_command
|
||||||
|
command: M106 S%(speed)s
|
||||||
|
input:
|
||||||
|
- name: Speed (0-255)
|
||||||
|
parameter: speed
|
||||||
|
default: 255
|
||||||
|
- name: Disable Fan
|
||||||
|
type: command
|
||||||
|
command: M107
|
||||||
|
|
||||||
# Absolute path where to store temporary timelapse files. Defaults to the timelapse/tmp folder in the OctoPrint
|
|
||||||
# settings dir
|
|
||||||
timelapse_tmp = /path/timelapse/tmp/folder
|
|
||||||
|
|
||||||
Setup on a Raspberry Pi running Raspbian
|
Setup on a Raspberry Pi running Raspbian
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
@ -158,10 +188,10 @@ This should hopefully run through without any compilation errors. You should the
|
||||||
If you now point your browser to `http://<your Raspi's IP>:8080/?action=stream`, you should see a moving picture at 5fps.
|
If you now point your browser to `http://<your Raspi's IP>:8080/?action=stream`, you should see a moving picture at 5fps.
|
||||||
Open `~/.octoprint/config.ini` and add the following lines to it:
|
Open `~/.octoprint/config.ini` and add the following lines to it:
|
||||||
|
|
||||||
[webcam]
|
webcam:
|
||||||
stream = http://<your Raspi's IP>:8080/?action=stream
|
stream: http://<your Raspi's IP>:8080/?action=stream
|
||||||
snapshot = http://127.0.0.1:8080/?action=snapshot
|
snapshot: http://127.0.0.1:8080/?action=snapshot
|
||||||
ffmpeg = /usr/bin/avconv
|
ffmpeg: /usr/bin/avconv
|
||||||
|
|
||||||
Restart the OctoPrint server and reload its frontend. You should now see a Webcam tab with content.
|
Restart the OctoPrint server and reload its frontend. You should now see a Webcam tab with content.
|
||||||
|
|
||||||
|
@ -179,6 +209,7 @@ It also uses the following libraries and frameworks for backend and frontend:
|
||||||
* Flask: http://flask.pocoo.org/
|
* Flask: http://flask.pocoo.org/
|
||||||
* Tornado: http://www.tornadoweb.org/
|
* Tornado: http://www.tornadoweb.org/
|
||||||
* Tornadio2: https://github.com/MrJoes/tornadio2
|
* Tornadio2: https://github.com/MrJoes/tornadio2
|
||||||
|
* PyYAML: http://pyyaml.org/
|
||||||
* Socket.io: http://socket.io/
|
* Socket.io: http://socket.io/
|
||||||
* jQuery: http://jquery.com/
|
* jQuery: http://jquery.com/
|
||||||
* Bootstrap: http://twitter.github.com/bootstrap/
|
* Bootstrap: http://twitter.github.com/bootstrap/
|
||||||
|
@ -201,14 +232,14 @@ What do I have to do after the rename from Printer WebUI to OctoPrint?
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
If you did checkout OctoPrint from its previous location at https://github.com/foosel/PrinterWebUI.git, you'll have to
|
If you did checkout OctoPrint from its previous location at https://github.com/foosel/PrinterWebUI.git, you'll have to
|
||||||
update your so-called remote references in git in order to make 'git pull' use the new repository location as origin.
|
update your so-called remote references in git in order to make `git pull` use the new repository location as origin.
|
||||||
|
|
||||||
To do so you'll only need to execute the following command in your OctoPrint/PrinterWebUI folder:
|
To do so you'll only need to execute the following command in your OctoPrint/PrinterWebUI folder:
|
||||||
|
|
||||||
git remote set-url origin https://github.com/foosel/OctoPrint.git
|
git remote set-url origin https://github.com/foosel/OctoPrint.git
|
||||||
|
|
||||||
After that you might also want to rename your base directory (which probably still is called 'PrinterWebUI') to 'OctoPrint'
|
After that you might also want to rename your base directory (which probably still is called `PrinterWebUI`) to `OctoPrint`
|
||||||
and delete the folder 'printer_webui' in your base folder (which stays there thanks to Python's compiled bytecode files
|
and delete the folder `printer_webui` in your base folder (which stays there thanks to Python's compiled bytecode files
|
||||||
even after a rename of the Python package to 'octoprint').
|
even after a rename of the Python package to `octoprint`).
|
||||||
|
|
||||||
After that you are set, the configuration files are migrated automatically :)
|
After that you are set, the configuration files are migrated automatically.
|
|
@ -120,6 +120,19 @@ def disconnect():
|
||||||
@app.route(BASEURL + "control/command", methods=["POST"])
|
@app.route(BASEURL + "control/command", methods=["POST"])
|
||||||
def printerCommand():
|
def printerCommand():
|
||||||
command = request.form["command"]
|
command = request.form["command"]
|
||||||
|
|
||||||
|
# if parameters for the command are given, retrieve them from the request and format the command string with them
|
||||||
|
parameters = {}
|
||||||
|
for requestParameter in request.values.keys():
|
||||||
|
if not requestParameter.startswith("parameter_"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
parameterName = requestParameter[len("parameter_"):]
|
||||||
|
parameterValue = request.values[requestParameter]
|
||||||
|
parameters[parameterName] = parameterValue
|
||||||
|
if len(parameters) > 0:
|
||||||
|
command = command % parameters
|
||||||
|
|
||||||
printer.command(command)
|
printer.command(command)
|
||||||
return jsonify(SUCCESS)
|
return jsonify(SUCCESS)
|
||||||
|
|
||||||
|
@ -182,6 +195,10 @@ def jog():
|
||||||
|
|
||||||
return jsonify(SUCCESS)
|
return jsonify(SUCCESS)
|
||||||
|
|
||||||
|
@app.route(BASEURL + "control/speed", methods=["GET"])
|
||||||
|
def getSpeedValues():
|
||||||
|
return jsonify(feedrate = printer.feedrateState())
|
||||||
|
|
||||||
@app.route(BASEURL + "control/speed", methods=["POST"])
|
@app.route(BASEURL + "control/speed", methods=["POST"])
|
||||||
def speed():
|
def speed():
|
||||||
if not printer.isOperational():
|
if not printer.isOperational():
|
||||||
|
@ -192,12 +209,11 @@ def speed():
|
||||||
value = int(request.values[key])
|
value = int(request.values[key])
|
||||||
printer.setFeedrateModifier(key, value)
|
printer.setFeedrateModifier(key, value)
|
||||||
|
|
||||||
return jsonify(feedrate = printer.feedrateState())
|
return getSpeedValues()
|
||||||
|
|
||||||
@app.route(BASEURL + "control/custom", methods=["GET"])
|
@app.route(BASEURL + "control/custom", methods=["GET"])
|
||||||
def getCustomControls():
|
def getCustomControls():
|
||||||
customControls = settings().getObject("controls")
|
customControls = settings().getObject("controls")
|
||||||
print("custom controls: %r" % customControls)
|
|
||||||
return jsonify(controls = customControls)
|
return jsonify(controls = customControls)
|
||||||
|
|
||||||
#~~ GCODE file handling
|
#~~ GCODE file handling
|
||||||
|
|
|
@ -45,46 +45,7 @@ old_default_settings = {
|
||||||
|
|
||||||
default_settings = old_default_settings.copy()
|
default_settings = old_default_settings.copy()
|
||||||
default_settings.update({
|
default_settings.update({
|
||||||
"controls": [
|
"controls": []
|
||||||
{
|
|
||||||
"name": "Motors",
|
|
||||||
"type": "section",
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"name": "Enable Motors",
|
|
||||||
"type": "command",
|
|
||||||
"command": "M17"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Disable Motors",
|
|
||||||
"type": "command",
|
|
||||||
"command": "M18"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Fan",
|
|
||||||
"type": "section",
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"name": "Enable Fan",
|
|
||||||
"type": "parameterized_command",
|
|
||||||
"command": "M106 S%(speed)",
|
|
||||||
"input": [{
|
|
||||||
"name": "Speed (0-255)",
|
|
||||||
"parameter": "speed",
|
|
||||||
"type": "integer",
|
|
||||||
"range": [0, 255]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Disable Fan",
|
|
||||||
"type": "command",
|
|
||||||
"command": "M107"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
|
|
||||||
class Settings(object):
|
class Settings(object):
|
||||||
|
@ -128,7 +89,7 @@ class Settings(object):
|
||||||
self._config[section][option] = config.get(section, option)
|
self._config[section][option] = config.get(section, option)
|
||||||
self._dirty = True
|
self._dirty = True
|
||||||
self.save(force=True)
|
self.save(force=True)
|
||||||
#os.rename(oldFilename, oldFilename + ".bck")
|
os.rename(oldFilename, oldFilename + ".bck")
|
||||||
else:
|
else:
|
||||||
self._config = {}
|
self._config = {}
|
||||||
|
|
||||||
|
@ -195,7 +156,7 @@ class Settings(object):
|
||||||
|
|
||||||
def set(self, section, key, value):
|
def set(self, section, key, value):
|
||||||
if section not in default_settings.keys():
|
if section not in default_settings.keys():
|
||||||
return None
|
return
|
||||||
|
|
||||||
if self._config.has_key(section):
|
if self._config.has_key(section):
|
||||||
sectionConfig = self._config[section]
|
sectionConfig = self._config[section]
|
||||||
|
@ -204,6 +165,14 @@ class Settings(object):
|
||||||
|
|
||||||
sectionConfig[key] = value
|
sectionConfig[key] = value
|
||||||
self._config[section] = sectionConfig
|
self._config[section] = sectionConfig
|
||||||
|
self._dirty = True
|
||||||
|
|
||||||
|
def setObject(self, key, value):
|
||||||
|
if key not in default_settings.keys():
|
||||||
|
return
|
||||||
|
|
||||||
|
self._config[key] = value
|
||||||
|
self._dirty = True
|
||||||
|
|
||||||
def _resolveSettingsDir(applicationName):
|
def _resolveSettingsDir(applicationName):
|
||||||
# taken from http://stackoverflow.com/questions/1084697/how-do-i-store-desktop-application-data-in-a-cross-platform-way-for-python
|
# taken from http://stackoverflow.com/questions/1084697/how-do-i-store-desktop-application-data-in-a-cross-platform-way-for-python
|
||||||
|
|
|
@ -387,16 +387,66 @@ function ControlsViewModel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
self._fromResponse = function(response) {
|
self._fromResponse = function(response) {
|
||||||
self.controls(response.controls);
|
self.controls(self._enhanceControls(response.controls));
|
||||||
|
}
|
||||||
|
|
||||||
|
self._enhanceControls = function(controls) {
|
||||||
|
for (var i = 0; i < controls.length; i++) {
|
||||||
|
controls[i] = self._enhanceControl(controls[i]);
|
||||||
|
}
|
||||||
|
return controls;
|
||||||
|
}
|
||||||
|
|
||||||
|
self._enhanceControl = function(control) {
|
||||||
|
if (control.type == "parametrized_command") {
|
||||||
|
for (var i = 0; i < control.input.length; i++) {
|
||||||
|
control.input[i].value = control.input[i].default;
|
||||||
|
}
|
||||||
|
} else if (control.type == "section") {
|
||||||
|
control.children = self._enhanceControls(control.children);
|
||||||
|
}
|
||||||
|
return control;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.sendJogCommand = function(axis, distance) {
|
||||||
|
$.ajax({
|
||||||
|
url: AJAX_BASEURL + "control/jog",
|
||||||
|
type: "POST",
|
||||||
|
dataType: "json",
|
||||||
|
data: axis + "=" + distance
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
self.sendHomeCommand = function(axis) {
|
||||||
|
$.ajax({
|
||||||
|
url: AJAX_BASEURL + "control/jog",
|
||||||
|
type: "POST",
|
||||||
|
dataType: "json",
|
||||||
|
data: "home" + axis
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
self.sendCustomCommand = function(command) {
|
self.sendCustomCommand = function(command) {
|
||||||
if (command) {
|
if (!command)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (command.type == "command") {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: AJAX_BASEURL + "control/command",
|
url: AJAX_BASEURL + "control/command",
|
||||||
type: "POST",
|
type: "POST",
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
data: "command=" + command
|
data: "command=" + command.command
|
||||||
|
})
|
||||||
|
} else if (command.type="parametrized_command") {
|
||||||
|
var data = {"command": command.command};
|
||||||
|
for (var i = 0; i < command.input.length; i++) {
|
||||||
|
data["parameter_" + command.input[i].parameter] = command.input[i].value;
|
||||||
|
}
|
||||||
|
$.ajax({
|
||||||
|
url: AJAX_BASEURL + "control/command",
|
||||||
|
type: "POST",
|
||||||
|
dataType: "json",
|
||||||
|
data: data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -406,8 +456,9 @@ function ControlsViewModel() {
|
||||||
case "section":
|
case "section":
|
||||||
return "customControls_sectionTemplate";
|
return "customControls_sectionTemplate";
|
||||||
case "command":
|
case "command":
|
||||||
case "parameterized_command":
|
|
||||||
return "customControls_commandTemplate";
|
return "customControls_commandTemplate";
|
||||||
|
case "parametrized_command":
|
||||||
|
return "customControls_parametrizedCommandTemplate";
|
||||||
default:
|
default:
|
||||||
return "customControls_emptyTemplate";
|
return "customControls_emptyTemplate";
|
||||||
}
|
}
|
||||||
|
@ -449,19 +500,28 @@ function SpeedViewModel() {
|
||||||
self.isLoading(data.flags.loading);
|
self.isLoading(data.flags.loading);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
self.requestData = function() {
|
||||||
if (response.feedrate) {
|
$.ajax({
|
||||||
self.outerWall(response.feedrate.outerWall);
|
url: AJAX_BASEURL + "control/speed",
|
||||||
self.innerWall(response.feedrate.innerWall);
|
type: "GET",
|
||||||
self.fill(response.feedrate.fill);
|
dataType: "json",
|
||||||
self.support(response.feedrate.support);
|
success: self._fromResponse
|
||||||
} else {
|
});
|
||||||
self.outerWall(undefined);
|
}
|
||||||
self.innerWall(undefined);
|
|
||||||
self.fill(undefined);
|
self._fromResponse = function(response) {
|
||||||
self.support(undefined);
|
if (response.feedrate) {
|
||||||
|
self.outerWall(response.feedrate.outerWall);
|
||||||
|
self.innerWall(response.feedrate.innerWall);
|
||||||
|
self.fill(response.feedrate.fill);
|
||||||
|
self.support(response.feedrate.support);
|
||||||
|
} else {
|
||||||
|
self.outerWall(undefined);
|
||||||
|
self.innerWall(undefined);
|
||||||
|
self.fill(undefined);
|
||||||
|
self.support(undefined);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function TerminalViewModel() {
|
function TerminalViewModel() {
|
||||||
|
@ -667,6 +727,7 @@ function WebcamViewModel() {
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
success: self.fromResponse
|
success: self.fromResponse
|
||||||
});
|
});
|
||||||
|
$("#webcam_image").attr("src", CONFIG_WEBCAM_STREAM + "?" + new Date().getTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.fromResponse = function(response) {
|
self.fromResponse = function(response) {
|
||||||
|
@ -847,33 +908,6 @@ $(function() {
|
||||||
temperatureViewModel.updatePlot();
|
temperatureViewModel.updatePlot();
|
||||||
});
|
});
|
||||||
|
|
||||||
//~~ Jog controls
|
|
||||||
|
|
||||||
function jogCommand(axis, distance) {
|
|
||||||
$.ajax({
|
|
||||||
url: AJAX_BASEURL + "control/jog",
|
|
||||||
type: "POST",
|
|
||||||
dataType: "json",
|
|
||||||
data: axis + "=" + distance
|
|
||||||
})
|
|
||||||
}
|
|
||||||
function homeCommand(axis) {
|
|
||||||
$.ajax({
|
|
||||||
url: AJAX_BASEURL + "control/jog",
|
|
||||||
type: "POST",
|
|
||||||
dataType: "json",
|
|
||||||
data: "home" + axis
|
|
||||||
})
|
|
||||||
}
|
|
||||||
$("#jog_x_inc").click(function() {jogCommand("x", "10")});
|
|
||||||
$("#jog_x_dec").click(function() {jogCommand("x", "-10")});
|
|
||||||
$("#jog_y_inc").click(function() {jogCommand("y", "10")});
|
|
||||||
$("#jog_y_dec").click(function() {jogCommand("y", "-10")});
|
|
||||||
$("#jog_z_inc").click(function() {jogCommand("z", "10")});
|
|
||||||
$("#jog_z_dec").click(function() {jogCommand("z", "-10")});
|
|
||||||
$("#jog_xy_home").click(function() {homeCommand("XY")});
|
|
||||||
$("#jog_z_home").click(function() {homeCommand("Z")});
|
|
||||||
|
|
||||||
//~~ Speed controls
|
//~~ Speed controls
|
||||||
|
|
||||||
function speedCommand(structure) {
|
function speedCommand(structure) {
|
||||||
|
@ -932,7 +966,7 @@ $(function() {
|
||||||
ko.applyBindings(printerStateViewModel, document.getElementById("state"));
|
ko.applyBindings(printerStateViewModel, document.getElementById("state"));
|
||||||
ko.applyBindings(gcodeFilesViewModel, document.getElementById("files"));
|
ko.applyBindings(gcodeFilesViewModel, document.getElementById("files"));
|
||||||
ko.applyBindings(temperatureViewModel, document.getElementById("temp"));
|
ko.applyBindings(temperatureViewModel, document.getElementById("temp"));
|
||||||
ko.applyBindings(controlsViewModel, document.getElementById("jog"));
|
ko.applyBindings(controlsViewModel, document.getElementById("controls"));
|
||||||
ko.applyBindings(terminalViewModel, document.getElementById("term"));
|
ko.applyBindings(terminalViewModel, document.getElementById("term"));
|
||||||
ko.applyBindings(speedViewModel, document.getElementById("speed"));
|
ko.applyBindings(speedViewModel, document.getElementById("speed"));
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,9 @@
|
||||||
<link href="{{ url_for('static', filename='css/ui.css') }}" rel="stylesheet" media="screen">
|
<link href="{{ url_for('static', filename='css/ui.css') }}" rel="stylesheet" media="screen">
|
||||||
|
|
||||||
<script lang="javascript">
|
<script lang="javascript">
|
||||||
var AJAX_BASEURL = '/ajax/';
|
var AJAX_BASEURL = "/ajax/";
|
||||||
var CONFIG_FILESPERPAGE = 5;
|
var CONFIG_FILESPERPAGE = 5;
|
||||||
|
var CONFIG_WEBCAM_STREAM = "{{ webcamStream }}";
|
||||||
|
|
||||||
var WEB_SOCKET_SWF_LOCATION = "{{ url_for('static', filename='js/WebSocketMain.swf') }}";
|
var WEB_SOCKET_SWF_LOCATION = "{{ url_for('static', filename='js/WebSocketMain.swf') }}";
|
||||||
var WEB_SOCKET_DEBUG = true;
|
var WEB_SOCKET_DEBUG = true;
|
||||||
|
@ -124,7 +125,7 @@
|
||||||
<div class="tabbable span8">
|
<div class="tabbable span8">
|
||||||
<ul class="nav nav-tabs" id="tabs">
|
<ul class="nav nav-tabs" id="tabs">
|
||||||
<li class="active"><a href="#temp" data-toggle="tab">Temperature</a></li>
|
<li class="active"><a href="#temp" data-toggle="tab">Temperature</a></li>
|
||||||
<li><a href="#jog" data-toggle="tab">Controls</a></li>
|
<li><a href="#controls" data-toggle="tab">Controls</a></li>
|
||||||
<!--<li><a href="#speed" data-toggle="tab">Speed</a></li>-->
|
<!--<li><a href="#speed" data-toggle="tab">Speed</a></li>-->
|
||||||
<li><a href="#term" data-toggle="tab">Terminal</a></li>
|
<li><a href="#term" data-toggle="tab">Terminal</a></li>
|
||||||
{% if webcamStream %}<li><a href="#webcam" data-toggle="tab">Webcam</a></li>{% endif %}
|
{% if webcamStream %}<li><a href="#webcam" data-toggle="tab">Webcam</a></li>{% endif %}
|
||||||
|
@ -166,24 +167,24 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-pane" id="jog">
|
<div class="tab-pane" id="controls">
|
||||||
<div style="width: 350px; height: 70px">
|
<div style="width: 350px; height: 70px">
|
||||||
<div style="width: 70px; float: left;"> </div>
|
<div style="width: 70px; float: left;"> </div>
|
||||||
<div style="width: 70px; float: left;"><button class="btn btn-block" id="jog_y_inc" data-bind="enable: isOperational() && !isPrinting()">Y+</button></div>
|
<div style="width: 70px; float: left;"><button class="btn btn-block" data-bind="enable: isOperational() && !isPrinting(), click: function() { $root.sendJogCommand('y', 10) }">Y+</button></div>
|
||||||
<div style="width: 70px; float: left;"> </div>
|
<div style="width: 70px; float: left;"> </div>
|
||||||
<div style="width: 70px; float: left; margin-left: 20px"><button class="btn btn-block" id="jog_z_inc" data-bind="enable: isOperational() && !isPrinting()">Z+</button></div>
|
<div style="width: 70px; float: left; margin-left: 20px"><button class="btn btn-block" data-bind="enable: isOperational() && !isPrinting(), click: function() { $root.sendJogCommand('z', 10) }">Z+</button></div>
|
||||||
</div>
|
</div>
|
||||||
<div style="width: 350px; height: 70px">
|
<div style="width: 350px; height: 70px">
|
||||||
<div style="width: 70px; float: left;"><button class="btn btn-block" id="jog_x_dec" data-bind="enable: isOperational() && !isPrinting()">X-</button></div>
|
<div style="width: 70px; float: left;"><button class="btn btn-block" data-bind="enable: isOperational() && !isPrinting(), click: function() { $root.sendJogCommand('x', -10) }">X-</button></div>
|
||||||
<div style="width: 70px; float: left;"><button class="btn btn-block" id="jog_xy_home" data-bind="enable: isOperational() && !isPrinting()">Home</button></div>
|
<div style="width: 70px; float: left;"><button class="btn btn-block" data-bind="enable: isOperational() && !isPrinting(), click: function() { $root.sendHomeCommand('XY') }">Home</button></div>
|
||||||
<div style="width: 70px; float: left;"><button class="btn btn-block" id="jog_x_inc" data-bind="enable: isOperational() && !isPrinting()">X+</button></div>
|
<div style="width: 70px; float: left;"><button class="btn btn-block" data-bind="enable: isOperational() && !isPrinting(), click: function() { $root.sendJogCommand('x', 10) }">X+</button></div>
|
||||||
<div style="width: 70px; float: left; margin-left: 20px"><button class="btn btn-block" id="jog_z_home" data-bind="enable: isOperational() && !isPrinting()">Home</button></div>
|
<div style="width: 70px; float: left; margin-left: 20px"><button class="btn btn-block" id="jog_z_home" data-bind="enable: isOperational() && !isPrinting(), click: function() { $root.sendHomeCommand('Z') }">Home</button></div>
|
||||||
</div>
|
</div>
|
||||||
<div style="width: 350px; height: 70px">
|
<div style="width: 350px; height: 70px">
|
||||||
<div style="width: 70px; float: left;"> </div>
|
<div style="width: 70px; float: left;"> </div>
|
||||||
<div style="width: 70px; float: left;"><button class="btn btn-block" id="jog_y_dec" data-bind="enable: isOperational() && !isPrinting()">Y-</button></div>
|
<div style="width: 70px; float: left;"><button class="btn btn-block" data-bind="enable: isOperational() && !isPrinting(), click: function() { $root.sendJogCommand('y', -10) }">Y-</button></div>
|
||||||
<div style="width: 70px; float: left;"> </div>
|
<div style="width: 70px; float: left;"> </div>
|
||||||
<div style="width: 70px; float: left; margin-left: 20px"><button class="btn btn-block" id="jog_z_dec" data-bind="enable: isOperational() && !isPrinting()">Z-</button></div>
|
<div style="width: 70px; float: left; margin-left: 20px"><button class="btn btn-block" data-bind="enable: isOperational() && !isPrinting(), click: function() { $root.sendJogCommand('z', -10) }">Z-</button></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div data-bind="template: { name: $root.displayMode, foreach: controls }"></div>
|
<div data-bind="template: { name: $root.displayMode, foreach: controls }"></div>
|
||||||
|
@ -195,9 +196,20 @@
|
||||||
<div data-bind="template: { name: $root.displayMode, foreach: children }"></div>
|
<div data-bind="template: { name: $root.displayMode, foreach: children }"></div>
|
||||||
</script>
|
</script>
|
||||||
<script type="text/html" id="customControls_commandTemplate">
|
<script type="text/html" id="customControls_commandTemplate">
|
||||||
<button class="btn" data-bind="text: name, enable: $root.isOperational(), click: function() { $root.sendCustomCommand($data.command) }"></button>
|
<form class="form-inline">
|
||||||
|
<button class="btn" data-bind="text: name, enable: $root.isOperational(), click: function() { $root.sendCustomCommand($data) }"></button>
|
||||||
|
</form>
|
||||||
</script>
|
</script>
|
||||||
<script type="text/html" id="customControls_emptyTemplate"></script>
|
<script type="text/html" id="customControls_parametrizedCommandTemplate">
|
||||||
|
<form class="form-inline">
|
||||||
|
<!-- ko foreach: input -->
|
||||||
|
<label data-bind="text: name"></label>
|
||||||
|
<input type="text" class="input-small" data-bind="attr: {placeholder: name}, value: value">
|
||||||
|
<!-- /ko -->
|
||||||
|
<button class="btn" data-bind="text: name, enable: $root.isOperational(), click: function() { $root.sendCustomCommand($data) }"></button>
|
||||||
|
</form>
|
||||||
|
</script>
|
||||||
|
<script type="text/html" id="customControls_emptyTemplate"><div></div></script>
|
||||||
<!-- End of templates for custom controls -->
|
<!-- End of templates for custom controls -->
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-pane" id="speed">
|
<div class="tab-pane" id="speed">
|
||||||
|
|
Loading…
Reference in New Issue