First parts of a webui for Cura
parent
5e1998d6a1
commit
580ebedfa9
|
@ -52,6 +52,8 @@ def main():
|
||||||
help="Internal option, do not use!")
|
help="Internal option, do not use!")
|
||||||
parser.add_option("-s", "--slice", action="store_true", dest="slice",
|
parser.add_option("-s", "--slice", action="store_true", dest="slice",
|
||||||
help="Slice the given files instead of opening them in Cura")
|
help="Slice the given files instead of opening them in Cura")
|
||||||
|
parser.add_option("-w", "--web", action="store_true", dest="webui",
|
||||||
|
help="Start the webui instead of the normal Cura UI")
|
||||||
(options, args) = parser.parse_args()
|
(options, args) = parser.parse_args()
|
||||||
|
|
||||||
if options.profile is not None:
|
if options.profile is not None:
|
||||||
|
@ -65,6 +67,9 @@ def main():
|
||||||
elif options.slice is not None:
|
elif options.slice is not None:
|
||||||
from Cura.util import sliceRun
|
from Cura.util import sliceRun
|
||||||
sliceRun.runSlice(args)
|
sliceRun.runSlice(args)
|
||||||
|
elif options.webui:
|
||||||
|
import Cura.webui as webapp
|
||||||
|
webapp.run()
|
||||||
else:
|
else:
|
||||||
#Place any unused arguments as last file, so Cura starts with opening those files.
|
#Place any unused arguments as last file, so Cura starts with opening those files.
|
||||||
if len(args) > 0:
|
if len(args) > 0:
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# coding=utf-8
|
||||||
|
__author__ = 'Gina Häußge <osd@foosel.net>'
|
||||||
|
|
||||||
|
from flask import Flask, request, render_template, jsonify
|
||||||
|
|
||||||
|
from printer import Printer
|
||||||
|
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
app = Flask("Cura.webui")
|
||||||
|
printer = Printer()
|
||||||
|
printer.connect()
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
def index():
|
||||||
|
return render_template('index.html')
|
||||||
|
|
||||||
|
@app.route('/api/printer/connect', methods=['POST'])
|
||||||
|
def connect():
|
||||||
|
printer.connect()
|
||||||
|
return jsonify(state='Connecting')
|
||||||
|
|
||||||
|
@app.route('/api/printer/disconnect', methods=['POST'])
|
||||||
|
def disconnect():
|
||||||
|
printer.disconnect()
|
||||||
|
return jsonify(state='Offline')
|
||||||
|
|
||||||
|
@app.route('/api/printer', methods=['GET'])
|
||||||
|
def printerState():
|
||||||
|
temp = printer.currentTemp
|
||||||
|
bedTemp = printer.currentBedTemp
|
||||||
|
jobData = printer.jobData()
|
||||||
|
|
||||||
|
if jobData != None:
|
||||||
|
return jsonify(state=printer.getStateString(),
|
||||||
|
operational=printer.isOperational(),
|
||||||
|
closedOrError=printer.isClosedOrError(),
|
||||||
|
temp=temp,
|
||||||
|
bedTemp=bedTemp,
|
||||||
|
job=jobData)
|
||||||
|
else:
|
||||||
|
return jsonify(state=printer.getStateString(),
|
||||||
|
temperature=temp,
|
||||||
|
bedTemperature=bedTemp)
|
||||||
|
|
||||||
|
@app.route('/api/printer/messages', methods=['GET'])
|
||||||
|
def printerMessages():
|
||||||
|
return jsonify(messages=printer.messages)
|
||||||
|
|
||||||
|
@app.route('/api/printer/log', methods=['GET'])
|
||||||
|
def printerMessages():
|
||||||
|
return jsonify(log=printer.log)
|
||||||
|
|
||||||
|
@app.route('/api/printer/command', methods=['POST'])
|
||||||
|
def printerCommand():
|
||||||
|
command = request.form['command']
|
||||||
|
printer.command(command)
|
||||||
|
return jsonify(state=printer.getStateString())
|
||||||
|
|
||||||
|
@app.route('/api/printer/temperatures', methods=['GET'])
|
||||||
|
def printerTemperatures():
|
||||||
|
return jsonify(temperatures = printer.temps)
|
||||||
|
|
||||||
|
@app.route('/api/printer/gcode', methods=['POST'])
|
||||||
|
def uploadGcodeFile():
|
||||||
|
file = request.files['gcode_file']
|
||||||
|
if file != None:
|
||||||
|
(handle, filename) = tempfile.mkstemp(suffix='.gcode', prefix='tmp_', text=True)
|
||||||
|
file.save(filename)
|
||||||
|
printer.loadGcode(filename)
|
||||||
|
return jsonify(state=printer.getStateString())
|
||||||
|
|
||||||
|
@app.route('/api/printer/print', methods=['POST'])
|
||||||
|
def printGcode():
|
||||||
|
printer.startPrint()
|
||||||
|
return jsonify(state=printer.getStateString())
|
||||||
|
|
||||||
|
@app.route('/api/printer/pause', methods=['POST'])
|
||||||
|
def pausePrint():
|
||||||
|
printer.togglePausePrint()
|
||||||
|
return jsonify(state=printer.getStateString())
|
||||||
|
|
||||||
|
@app.route('/api/printer/cancel', methods=['POST'])
|
||||||
|
def cancelPrint():
|
||||||
|
printer.cancelPrint()
|
||||||
|
return jsonify(state=printer.getStateString())
|
||||||
|
|
||||||
|
def run():
|
||||||
|
app.debug = True
|
||||||
|
app.run()
|
|
@ -0,0 +1,208 @@
|
||||||
|
# coding=utf-8
|
||||||
|
__author__ = 'Gina Häußge <osd@foosel.net>'
|
||||||
|
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
|
||||||
|
import Cura.util.machineCom as machineCom
|
||||||
|
from Cura.util import gcodeInterpreter
|
||||||
|
|
||||||
|
class Printer():
|
||||||
|
def __init__(self):
|
||||||
|
# state
|
||||||
|
self.temps = {
|
||||||
|
'actual': [],
|
||||||
|
'target': [],
|
||||||
|
'actualBed': [],
|
||||||
|
'targetBed': []
|
||||||
|
}
|
||||||
|
self.messages = []
|
||||||
|
self.log = []
|
||||||
|
self.state = None
|
||||||
|
self.currentZ = None
|
||||||
|
self.progress = None
|
||||||
|
self.printTime = None
|
||||||
|
self.printTimeLeft = None
|
||||||
|
self.currentTemp = None
|
||||||
|
self.currentBedTemp = None
|
||||||
|
|
||||||
|
self.gcode = None
|
||||||
|
self.gcodeList = None
|
||||||
|
self.filename = None
|
||||||
|
|
||||||
|
# comm
|
||||||
|
self.comm = None
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
if self.comm != None:
|
||||||
|
self.comm.close()
|
||||||
|
self.comm = machineCom.MachineCom(port='VIRTUAL', callbackObject=self)
|
||||||
|
|
||||||
|
def disconnect(self):
|
||||||
|
if self.comm != None:
|
||||||
|
self.comm.close()
|
||||||
|
self.comm = None
|
||||||
|
|
||||||
|
def command(self, command):
|
||||||
|
self.comm.sendCommand(command)
|
||||||
|
|
||||||
|
def mcLog(self, message):
|
||||||
|
self.log.append(message)
|
||||||
|
self.log = self.log[-300:]
|
||||||
|
|
||||||
|
def mcTempUpdate(self, temp, bedTemp, targetTemp, bedTargetTemp):
|
||||||
|
currentTime = time.time()
|
||||||
|
|
||||||
|
self.temps['actual'].append((currentTime, temp))
|
||||||
|
self.temps['actual'] = self.temps['actual'][-300:]
|
||||||
|
|
||||||
|
self.temps['target'].append((currentTime, targetTemp))
|
||||||
|
self.temps['target'] = self.temps['target'][-300:]
|
||||||
|
|
||||||
|
self.temps['actualBed'].append((currentTime, bedTemp))
|
||||||
|
self.temps['actualBed'] = self.temps['actualBed'][-300:]
|
||||||
|
|
||||||
|
self.temps['targetBed'].append((currentTime, bedTargetTemp))
|
||||||
|
self.temps['targetBed'] = self.temps['targetBed'][-300:]
|
||||||
|
|
||||||
|
self.currentTemp = temp
|
||||||
|
self.currentBedTemp = bedTemp
|
||||||
|
|
||||||
|
def mcStateChange(self, state):
|
||||||
|
self.state = state
|
||||||
|
|
||||||
|
def mcMessage(self, message):
|
||||||
|
self.messages.append(message)
|
||||||
|
self.messages = self.message[-300:]
|
||||||
|
|
||||||
|
def mcProgress(self, lineNr):
|
||||||
|
self.printTime = self.comm.getPrintTime()
|
||||||
|
self.printTimeLeft = self.comm.getPrintTimeRemainingEstimate()
|
||||||
|
self.progress = self.comm.getPrintPos()
|
||||||
|
|
||||||
|
def mcZChange(self, newZ):
|
||||||
|
self.currentZ = newZ
|
||||||
|
|
||||||
|
def jobData(self):
|
||||||
|
if self.gcode != None:
|
||||||
|
formattedPrintTime = None
|
||||||
|
if (self.printTime):
|
||||||
|
"%02d:%02d" % (int(self.printTime / 60), int(self.printTime % 60))
|
||||||
|
|
||||||
|
formattedPrintTimeLeft = None
|
||||||
|
if (self.printTimeLeft):
|
||||||
|
"%02d:%02d" % (int(self.printTimeLeft / 60), int(self.printTimeLeft % 60))
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'currentZ': self.currentZ,
|
||||||
|
'line': self.progress,
|
||||||
|
'totalLines': len(self.gcodeList),
|
||||||
|
'printTime': formattedPrintTime,
|
||||||
|
'printTimeLeft': formattedPrintTimeLeft,
|
||||||
|
'filament': "%.2fm %.2fg" % (
|
||||||
|
self.gcode.extrusionAmount / 1000,
|
||||||
|
self.gcode.calculateWeight() * 1000
|
||||||
|
),
|
||||||
|
'estimatedPrintTime': "%02d:%02d" % (
|
||||||
|
int(self.gcode.totalMoveTimeMinute / 60),
|
||||||
|
int(self.gcode.totalMoveTimeMinute % 60)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
data = None
|
||||||
|
return data
|
||||||
|
|
||||||
|
def getStateString(self):
|
||||||
|
if self.comm == None:
|
||||||
|
return 'Offline'
|
||||||
|
else:
|
||||||
|
return self.comm.getStateString()
|
||||||
|
|
||||||
|
def isClosedOrError(self):
|
||||||
|
return self.comm == None or self.comm.isClosedOrError()
|
||||||
|
|
||||||
|
def isOperational(self):
|
||||||
|
return self.comm != None and self.comm.isOperational()
|
||||||
|
|
||||||
|
def loadGcode(self, file):
|
||||||
|
if self.comm != None and self.comm.isPrinting():
|
||||||
|
return
|
||||||
|
|
||||||
|
# delete old temporary file
|
||||||
|
if self.filename != None:
|
||||||
|
os.remove(self.filename)
|
||||||
|
|
||||||
|
#Send an initial M110 to reset the line counter to zero.
|
||||||
|
prevLineType = lineType = 'CUSTOM'
|
||||||
|
gcodeList = ["M110"]
|
||||||
|
for line in open(file, 'r'):
|
||||||
|
if line.startswith(';TYPE:'):
|
||||||
|
lineType = line[6:].strip()
|
||||||
|
if ';' in line:
|
||||||
|
line = line[0:line.find(';')]
|
||||||
|
line = line.strip()
|
||||||
|
if len(line) > 0:
|
||||||
|
if prevLineType != lineType:
|
||||||
|
gcodeList.append((line, lineType, ))
|
||||||
|
else:
|
||||||
|
gcodeList.append(line)
|
||||||
|
prevLineType = lineType
|
||||||
|
gcode = gcodeInterpreter.gcode()
|
||||||
|
gcode.loadList(gcodeList)
|
||||||
|
#print "Loaded: %s (%d)" % (filename, len(gcodeList))
|
||||||
|
self.filename = file
|
||||||
|
self.gcode = gcode
|
||||||
|
self.gcodeList = gcodeList
|
||||||
|
|
||||||
|
def startPrint(self):
|
||||||
|
if self.comm == None or not self.comm.isOperational():
|
||||||
|
return
|
||||||
|
if self.gcodeList == None:
|
||||||
|
return
|
||||||
|
if self.comm.isPrinting():
|
||||||
|
return
|
||||||
|
self.currentZ = -1
|
||||||
|
self.comm.printGCode(self.gcodeList)
|
||||||
|
|
||||||
|
def togglePausePrint(self):
|
||||||
|
if self.comm == None:
|
||||||
|
return
|
||||||
|
self.comm.setPause(not self.comm.isPaused())
|
||||||
|
|
||||||
|
def cancelPrint(self):
|
||||||
|
if self.comm == None:
|
||||||
|
return
|
||||||
|
self.comm.cancelPrint()
|
||||||
|
self.comm.sendCommand("M84")
|
||||||
|
|
||||||
|
class Temperature():
|
||||||
|
def __init__(self, actual=None, target=None):
|
||||||
|
self._actual = actual
|
||||||
|
self._target = target
|
||||||
|
|
||||||
|
def actual(self):
|
||||||
|
return self._actual
|
||||||
|
|
||||||
|
def target(self):
|
||||||
|
return self._target
|
||||||
|
|
||||||
|
def asDict(self):
|
||||||
|
return {'actual': self._actual, 'target': self._target}
|
||||||
|
|
||||||
|
class Position():
|
||||||
|
def __init__(self, x=None, y=None, z=None):
|
||||||
|
self._x = x
|
||||||
|
self._y = y
|
||||||
|
self._z = z
|
||||||
|
|
||||||
|
def update(self, x=None, y=None, z=None):
|
||||||
|
if x != None:
|
||||||
|
self._x = x
|
||||||
|
if y != None:
|
||||||
|
self._y = y
|
||||||
|
if z != None:
|
||||||
|
self._z = z
|
||||||
|
|
||||||
|
def get(self):
|
||||||
|
return {'x': self._x, 'y': self._y, 'z': self._z}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Binary file not shown.
After Width: | Height: | Size: 8.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,88 @@
|
||||||
|
var printerstate = function() {
|
||||||
|
|
||||||
|
var updateInterval = 500;
|
||||||
|
function update() {
|
||||||
|
function onDataReceived(response) {
|
||||||
|
$("#printer_state").text(response.state);
|
||||||
|
$("#printer_temp").text(response.temp + " °C");
|
||||||
|
$("#printer_bedTemp").text(response.bedTemp + " °C");
|
||||||
|
|
||||||
|
if (response.job) {
|
||||||
|
var currentLine = (response.job.line ? response.job.line : 0);
|
||||||
|
var progress = currentLine * 100 / response.job.totalLines;
|
||||||
|
$("#job_filament").text(response.job.filament);
|
||||||
|
$("#job_estimatedPrintTime").text(response.job.estimatedPrintTime);
|
||||||
|
$("#job_line").text((currentLine == 0 ? "-" : currentLine) + "/" + response.job.totalLines + " " + progress + "%");
|
||||||
|
$("#job_height").text(response.job.currentZ);
|
||||||
|
$("#job_printTime").text(response.job.printTime);
|
||||||
|
$("#job_printTimeLeft").text(response.job.printTimeLeft);
|
||||||
|
$("#job_progressBar").width(progress + "%");
|
||||||
|
} else {
|
||||||
|
$("#job_filament").text("-");
|
||||||
|
$("#job_estimatedPrintTime").text("-");
|
||||||
|
$("#job_line").text("-");
|
||||||
|
$("#job_height").text("-");
|
||||||
|
$("#job_printTime").text("-");
|
||||||
|
$("#job_printTimeLefT").text("-");
|
||||||
|
$("#job_progressBar").width("0%");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response.closedOrError) {
|
||||||
|
$("#printer_connect").click(function(){});
|
||||||
|
$("#printer_connect").addClass("disabled");
|
||||||
|
} else {
|
||||||
|
$("#printer_connect").click(connect);
|
||||||
|
$("#printer_connect").removeClass("disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#job_print").click(function() {
|
||||||
|
$.ajax({
|
||||||
|
url: "/api/printer/print",
|
||||||
|
type: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
|
success: function(){}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
$("#job_pause").click(function() {
|
||||||
|
$.ajax({
|
||||||
|
url: "/api/printer/pause",
|
||||||
|
type: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
|
success: function(){}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
$("#job_cancel").click(function() {
|
||||||
|
$.ajax({
|
||||||
|
url: "/api/printer/cancel",
|
||||||
|
type: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
|
success: function(){}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: "/api/printer",
|
||||||
|
method: 'GET',
|
||||||
|
dataType: 'json',
|
||||||
|
success: onDataReceived
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(update, updateInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
function connect() {
|
||||||
|
$.ajax({
|
||||||
|
url: "/api/printer/connect",
|
||||||
|
type: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
|
success: function(response) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
printerstate();
|
|
@ -0,0 +1,45 @@
|
||||||
|
|
||||||
|
var temperaturegraph = function() {
|
||||||
|
|
||||||
|
var options = {
|
||||||
|
yaxis: {
|
||||||
|
min: 0,
|
||||||
|
max: 310,
|
||||||
|
ticks: 10
|
||||||
|
},
|
||||||
|
xaxis: {
|
||||||
|
mode: "time"
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
noColumns: 4
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var updateInterval = 500;
|
||||||
|
function update() {
|
||||||
|
function onDataReceived(response) {
|
||||||
|
var temps = response.temperatures;
|
||||||
|
var data = [
|
||||||
|
{label: "Actual", color: "#FF4040", data: temps.actual},
|
||||||
|
{label: "Target", color: "#FFA0A0", data: temps.target},
|
||||||
|
{label: "Bed Actual", color: "#4040FF", data: temps.actualBed},
|
||||||
|
{label: "Bed Target", color: "#A0A0FF", data: temps.targetBed}
|
||||||
|
]
|
||||||
|
$.plot($("#temperature-graph"), data, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: "/api/printer/temperatures",
|
||||||
|
method: 'GET',
|
||||||
|
dataType: 'json',
|
||||||
|
success: onDataReceived
|
||||||
|
})
|
||||||
|
|
||||||
|
setTimeout(update, updateInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
update();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
temperaturegraph();
|
|
@ -0,0 +1,49 @@
|
||||||
|
var terminaloutput = function() {
|
||||||
|
|
||||||
|
var updateInterval = 1000;
|
||||||
|
function update() {
|
||||||
|
function onDataReceived(response) {
|
||||||
|
var log = response.log;
|
||||||
|
var output = '';
|
||||||
|
for (var i = 0; i < log.length; i++) {
|
||||||
|
output += log[i] + '<br>';
|
||||||
|
}
|
||||||
|
|
||||||
|
var container = $("#terminal-output");
|
||||||
|
var autoscroll = (container.scrollTop() == container[0].scrollHeight - container.height);
|
||||||
|
|
||||||
|
container.html(output);
|
||||||
|
|
||||||
|
if (autoscroll) {
|
||||||
|
container.scrollTop(container[0].scrollHeight - container.height())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: "/api/printer/log",
|
||||||
|
type: 'GET',
|
||||||
|
dataType: 'json',
|
||||||
|
success: onDataReceived
|
||||||
|
})
|
||||||
|
|
||||||
|
setTimeout(update, updateInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
update();
|
||||||
|
|
||||||
|
$("#terminal-send").click(function () {
|
||||||
|
var command = $("#terminal-command").val();
|
||||||
|
$.ajax({
|
||||||
|
url: "/api/printer/command",
|
||||||
|
type: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
|
data: 'command=' + command,
|
||||||
|
success: function(response) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
terminaloutput();
|
|
@ -0,0 +1,121 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Bootstrap 101 Template</title>
|
||||||
|
<link href="{{ url_for('static', filename='css/bootstrap.min.css') }}" rel="stylesheet" media="screen">
|
||||||
|
<script src="http://code.jquery.com/jquery-latest.js"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/bootstrap.js') }}"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/jquery.flot.js') }}"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row-fluid">
|
||||||
|
<h1>Cura WebUI</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row-fluid">
|
||||||
|
<div class="span3">
|
||||||
|
<h2>Printer</h2>
|
||||||
|
Machine State: <strong id="printer_state"></strong><br>
|
||||||
|
<button class="btn" id="printer_connect">Connect</button>
|
||||||
|
|
||||||
|
<h2>Job</h2>
|
||||||
|
Filament: <strong id="job_filament"></strong><br>
|
||||||
|
Estimated Print Time: <strong id="job_estimatedPrintTime"></strong><br>
|
||||||
|
Line: <strong id="job_line"></strong><br>
|
||||||
|
Height: <strong id="job_currentZ"></strong><br>
|
||||||
|
Print Time: <strong id="job_printTime"></strong><br>
|
||||||
|
Print Time Left: <strong id="job_printTimeLeft"></strong><br>
|
||||||
|
|
||||||
|
<div class="progress">
|
||||||
|
<div class="bar" id="job_progressBar" style="width: 30%;"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="btn" id="job_print">Print</button>
|
||||||
|
<button class="btn" id="job_pause">Pause</button>
|
||||||
|
<button class="btn" id="job_cancel">Cancel</button>
|
||||||
|
|
||||||
|
<form action="/api/printer/gcode" method="post" enctype="multipart/form-data">
|
||||||
|
<input type="file" name="gcode_file">
|
||||||
|
<button class="btn" type="submit">Load</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="span9 tabbable tabs-left">
|
||||||
|
|
||||||
|
<ul class="nav nav-tabs">
|
||||||
|
<li class="active"><a href="#temp" data-toggle="tab">Temp</a></li>
|
||||||
|
<li><a href="#jog" data-toggle="tab">Jog</a></li>
|
||||||
|
<li><a href="#speed" data-toggle="tab">Speed</a></li>
|
||||||
|
<li><a href="#term" data-toggle="tab">Term</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="tab-content">
|
||||||
|
<div class="tab-pane active" id="temp">
|
||||||
|
<div id="temperature-graph" class="span6 " style="height: 350px"></div>
|
||||||
|
<div class="span3">
|
||||||
|
Temp: <strong id="printer_temp"></strong><br>
|
||||||
|
Bed Temp: <strong id="printer_bedTemp"></strong><br>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane" id="jog">
|
||||||
|
<div class="span9">
|
||||||
|
<div class="row">
|
||||||
|
<div class="span1 offset1 btn-group btn-group-vertical">
|
||||||
|
<button class="btn btn-block btn-large" type="button"><i class="icon-chevron-up"></i></button>
|
||||||
|
<button class="btn btn-block" type="button"><i class="icon-chevron-up"></i></button>
|
||||||
|
<button class="btn btn-block btn-small" type="button"><i class="icon-chevron-up"></i></button>
|
||||||
|
</div>
|
||||||
|
<div class="span1 offset1 btn-group btn-group-vertical">
|
||||||
|
<button class="btn btn-block btn-large" type="button"><i class="icon-chevron-up"></i></button>
|
||||||
|
<button class="btn btn-block" type="button"><i class="icon-chevron-up"></i></button>
|
||||||
|
<button class="btn btn-block btn-small" type="button"><i class="icon-chevron-up"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="span1 btn-group btn-group">
|
||||||
|
<button class="btn" type="button"><i class="icon-chevron-left"></i></button>
|
||||||
|
<button class="btn" type="button"><i class="icon-chevron-left"></i></button>
|
||||||
|
<button class="btn" type="button"><i class="icon-chevron-left"></i></button>
|
||||||
|
</div>
|
||||||
|
<div class="span1">
|
||||||
|
<button class="btn btn-block" type="button"><i class="icon-home"></i></button>
|
||||||
|
</div>
|
||||||
|
<div class="span1 btn-group btn-group">
|
||||||
|
<button class="btn" type="button"><i class="icon-chevron-right"></i></button>
|
||||||
|
<button class="btn" type="button"><i class="icon-chevron-right"></i></button>
|
||||||
|
<button class="btn" type="button"><i class="icon-chevron-right"></i></button>
|
||||||
|
</div>
|
||||||
|
<div class="span1">
|
||||||
|
<button class="btn btn-block" type="button"><i class="icon-home"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="span1 offset1 btn-group btn-group-vertical">
|
||||||
|
<button class="btn btn-block btn-small" type="button"><i class="icon-chevron-down"></i></button>
|
||||||
|
<button class="btn btn-block" type="button"><i class="icon-chevron-down"></i></button>
|
||||||
|
<button class="btn btn-block btn-large" type="button"><i class="icon-chevron-down"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane" id="speed">
|
||||||
|
Here be speed settings
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane" id="term">
|
||||||
|
<pre id="terminal-output" class="pre-scrollable"></pre>
|
||||||
|
<div class="input-append">
|
||||||
|
<input type="text" class="span9" id="terminal-command">
|
||||||
|
<button class="btn" type="button" id="terminal-send">Send</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Here be scripts -->
|
||||||
|
<script src="{{ url_for('static', filename='js/printerstate.js') }}"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/temperaturegraph.js') }}"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/terminaloutput.js') }}"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,3 +1,4 @@
|
||||||
|
flask>=0.9
|
||||||
PyOpenGL>=3.0.2
|
PyOpenGL>=3.0.2
|
||||||
numpy>=1.6.2
|
numpy>=1.6.2
|
||||||
pyserial>=2.6
|
pyserial>=2.6
|
||||||
|
|
Loading…
Reference in New Issue