Getting the print queue api working with the printer, adding a job progress panel to inspector and adding job_finished and job_started events.

master
D1plo1d 2013-04-19 13:26:03 -04:00
parent 5867975a10
commit f01e5747e3
5 changed files with 260 additions and 29 deletions

View File

@ -26,6 +26,7 @@ import socket
import mdns
import uuid
from operator import itemgetter, attrgetter
from collections import deque
log = logging.getLogger("root")
__UPLOADS__ = "./uploads"
@ -68,6 +69,21 @@ class RootHandler(tornado.web.RequestHandler):
def get(self):
self.render("index.html")
class PrintHandler(tornado.web.RequestHandler):
def put(self):
pronserve.do_print()
self.finish("ACK")
class PauseHandler(tornado.web.RequestHandler):
def put(self):
pronserve.do_pause()
self.finish("ACK")
class StopHandler(tornado.web.RequestHandler):
def put(self):
pronserve.do_stop()
self.finish("ACK")
class JobsHandler(tornado.web.RequestHandler):
def post(self):
fileinfo = self.request.files['job'][0]
@ -106,8 +122,33 @@ class ConstructSocketHandler(tornado.websocket.WebSocketHandler):
self.write_message({'connected': {'jobs': pronserve.jobs.public_list()}})
print "WebSocket opened. %i sockets currently open." % len(pronserve.clients)
def on_sensor_change(self):
self.write_message({'sensors': pronserve.sensors, 'timestamp': time.time()})
def on_sensor_changed(self):
print "sensor change"
self.write_message({
'sensor_changed': {'name': 'bed', 'value': pronserve.sensors['bed']},
'timestamp': time.time()
})
self.write_message({
'sensor_changed': {'name': 'extruder', 'value': pronserve.sensors['extruder']},
'timestamp': time.time()
})
def on_job_progress_changed(self, progress):
self.write_message({
'job_progress_changed': progress,
'timestamp': time.time()
})
def on_job_started(self, job):
self.write_message({
'job_started': job,
'timestamp': time.time()
})
def on_job_finished(self, job):
self.write_message({
'job_finished': job,
'timestamp': time.time()
})
def on_job_added(self, job):
self.write_message({'job_added': pronserve.jobs.sanitize(job)})
@ -124,11 +165,12 @@ class ConstructSocketHandler(tornado.websocket.WebSocketHandler):
def on_pronsole_log(self, msg):
self.write_message({'log': {msg: msg, level: "debug"}})
self.write_message({'log': {'msg': msg, 'level': "debug"}})
def on_message(self, msg):
print "message received: %s"%(msg)
# TODO: the read bit of repl!
self.write_message("You said: " + msg)
# self.write_message("You said: " + msg)
def on_close(self):
pronserve.clients.remove(self)
@ -146,7 +188,10 @@ application = tornado.web.Application([
(r"/inspect", InspectHandler),
(r"/socket", ConstructSocketHandler),
(r"/jobs", JobsHandler),
(r"/jobs/([0-9]*)", JobHandler)
(r"/jobs/([0-9]*)", JobHandler),
(r"/jobs/print", PrintHandler),
(r"/jobs/pause", PauseHandler),
(r"/stop", StopHandler)
], **settings)
@ -161,15 +206,53 @@ class Pronserve(pronsole.pronsole):
self.stdout = sys.stdout
self.ioloop = tornado.ioloop.IOLoop.instance()
self.clients = set()
self.settings.sensor_poll_rate = 0.3 # seconds
self.settings.sensor_poll_rate = 1 # seconds
self.sensors = {'extruder': -1, 'bed': -1}
self.load_default_rc()
self.jobs = PrintJobQueue()
self.job_id_incr = 0;
self.job_id_incr = 0
self.printing_jobs = False
self.current_job = None
self.previous_job_progress = 0
services = ({'type': '_construct._tcp', 'port': 8888, 'domain': "local."})
self.mdns = mdns.publisher().save_group({'name': 'pronserve', 'services': services })
self.jobs.listeners.append(self)
def do_print(self):
if self.p.online:
self.printing_jobs = True
def run_print_queue_loop(self):
# This is a polling work around to the current lack of events in printcore
# A better solution would be one in which a print_finised event could be
# listend for asynchronously without polling.
p = self.p
if self.printing_jobs and p.printing == False and p.paused == False and p.online:
if self.current_job != None:
self.update_job_progress(100)
self.fire("job_finished", self.jobs.sanitize(self.current_job))
if len(self.jobs.list) > 0:
print "Starting the next print job"
self.current_job = self.jobs.list.popleft()
self.p.startprint(self.current_job['body'].split("\n"))
self.fire("job_started", self.jobs.sanitize(self.current_job))
else:
print "Finished all print jobs"
self.current_job = None
self.printing_jobs = False
# Updating the job progress
self.update_job_progress(self.print_progress())
#print "print loop"
next_timeout = time.time() + 0.3
gen.Task(self.ioloop.add_timeout(next_timeout, self.run_print_queue_loop))
def update_job_progress(self, progress):
if progress != self.previous_job_progress and self.current_job != None:
self.previous_job_progress = progress
self.fire("job_progress_changed", progress)
def run_sensor_loop(self):
self.request_sensor_update()
next_timeout = time.time() + self.settings.sensor_poll_rate
@ -181,23 +264,34 @@ class Pronserve(pronsole.pronsole):
def recvcb(self, l):
""" Parses a line of output from the printer via printcore """
l = l.rstrip()
print l
if "T:" in l:
self._receive_sensor_update(l)
if l!="ok" and not l.startswith("ok T") and not l.startswith("T:"):
self._receive_printer_error(l)
def print_progress(self):
if(self.p.printing):
return 100*float(self.p.queueindex)/len(self.p.mainqueue)
if(self.sdprinting):
return self.percentdone
return 0
def _receive_sensor_update(self, l):
words = l.split(" ")
words.pop(0)
words = filter(lambda s: s.find(":") > 0, l.split(" "))
d = dict([ s.split(":") for s in words])
print "sensor update received!"
for key, value in d.iteritems():
self.__update_sensor(key, value)
self.fire("sensor_change")
self.fire("sensor_changed")
def __update_sensor(self, key, value):
if (key in self.settings.sensor_names) == False:
return
sensor_name = self.settings.sensor_names[key]
self.sensors[sensor_name] = float(value)
@ -219,10 +313,11 @@ class Pronserve(pronsole.pronsole):
def write_prompt(self):
None
class PrintJobQueue():
def __init__(self):
self.list = []
self.list = deque([])
self.__last_id = 0
self.listeners = []
@ -246,20 +341,16 @@ class PrintJobQueue():
def add(self, original_file_name, body):
ext = os.path.splitext(original_file_name)[1]
file_name = str(uuid.uuid4()) + ext
job = dict(
id = self.__last_id,
rank = len(self.list),
original_file_name=original_file_name,
path= __UPLOADS__ + "/" + file_name,
body= body,
)
self.__last_id += 1
fh = open(job['path'], 'w')
fh.write(body)
self.list.append(job)
print "Added %s as %s"%(original_file_name, file_name)
print "Added %s"%(original_file_name)
self.fire("job_added", job)
def display_summary(self):
@ -305,8 +396,9 @@ print "Pronserve is starting..."
pronserve = Pronserve()
pronserve.do_connect("")
time.sleep(0.2)
time.sleep(1)
pronserve.run_sensor_loop()
pronserve.run_print_queue_loop()
if __name__ == "__main__":
application.listen(8888)

View File

@ -38,4 +38,17 @@
#temperature-graph
{
height: 200px;
}
#print-job-panel
{
margin: 0px;
}
.job-pogress
{
margin: 80px 0;
font-size: 40px;
line-height: 40px;
text-align: center;
}

View File

@ -6,11 +6,15 @@
$(window).focus(function() {
windowFocus = true;
//if ($console) $console.append("Window refocused, restarting graph.\n");
$(".focus-lost-overlay").addClass("out").removeClass("in");
$(".focus-lost-overlay").addClass("out").removeClass("in").delay(1000).hide();
}).blur(function() {
windowFocus = false;
//if ($console) $console.append("Window's focus, lost stopping graph...\n");
$(".focus-lost-overlay").addClass("in").removeClass("out");
$(".focus-lost-overlay")
.stop(true,true)
.show()
.addClass("in")
.removeClass("out");
}.debounce());
var connect = function() {
@ -75,7 +79,6 @@
if(windowFocus == false) return;
updateSensorsUi();
updateGraphUi();
$consoleWrapper.scrollTop($console.innerHeight());
}
var onConnect = function(ws) {
@ -85,26 +88,42 @@
// Web Socket is connected, send data using send()
};
var nextGraphPoint = {};
ws.onmessage = function (evt)
{
msg = JSON.parse(evt.data)
if(msg.sensors != undefined)
if(msg.sensor_changed != undefined)
{
var sensorNames = ["bed", "extruder"];
var values = {timestamp: msg.timestamp};
for (var i = 0; i < sensorNames.length; i++)
{
var name = sensorNames[i];
var val = parseFloat(msg.sensors[name]);
values[name] = val;
var name = msg.sensor_changed.name;
var val = parseFloat(msg.sensor_changed.value);
nextGraphPoint[name] = val;
$("."+name+" .val").data("val", val.format(1))
}
updateGraphData(values);
if(nextGraphPoint.bed != undefined && nextGraphPoint.extruder != undefined)
{
nextGraphPoint.timestamp = msg.timestamp
updateGraphData(nextGraphPoint);
nextGraphPoint = {};
}
requestAnimationFrame(updateUi);
}
else if (msg.job_progress_changed != undefined)
{
val = Math.round(parseFloat(msg.job_progress_changed)*10)/10;
$(".job-pogress .val").html(val);
}
else
{
console.log($consoleWrapper.scrollTop() - $console.innerHeight())
var atBottom = $consoleWrapper.scrollTop() - $console.innerHeight() > -220;
$console.append(evt.data + "\n");
if (atBottom)
{
$consoleWrapper.scrollTop($console.innerHeight());
}
}
};
ws.onclose = function()

View File

@ -21,6 +21,12 @@
Connecting...
</pre>
</div>
</div>
<div class="span3" id="print-job-panel">
<h2>Job Progress</h2>
<div class="job-pogress"><span class="val">XX.X</span>%</div>
</div>
<div class="span9">
<div class="sensors pull-right">
<div class="extruder pull-right">
Extruder: <span class="val">xx.x</span><span class="deg">&deg;C</span>
@ -38,7 +44,7 @@
</div>
<div class="focus-lost-overlay modal-backdrop fade out"></div>
<div class="focus-lost-overlay modal-backdrop fade out hide"></div>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/js/bootstrap.min.js"></script>

101
testfiles/quick-test.gcode Normal file
View File

@ -0,0 +1,101 @@
; THIS IS A TZST. DO NOT ATTZMPT TO PRINT THIS FILZ.
; gZnZratZd by Slic3r 0.9.3-dZv on 2012-09-02 at 04:02:31
; layZr_hZight = 0.4
; pZrimZtZrs = 3
; solid_layZrs = 3
; fill_dZnsity = 0.4
; pZrimZtZr_spZZd = 30
; infill_spZZd = 60
; travZl_spZZd = 130
; scalZ = 1
; nozzlZ_diamZtZr = 0.5
; filamZnt_diamZtZr = 3
; Zxtrusion_multipliZr = 1
; singlZ wall width = 0.53mm
; first layZr singlZ wall width = 0.80mm
M104 S200 ; sZt tZmpZraturZ
;G28 ; homZ all axZs
;M109 S200 ; wait for tZmpZraturZ to bZ rZachZd
G90 ; usZ absolutZ coordinatZs
G21 ; sZt units to millimZtZrs
G92 Z0
M82 ; usZ absolutZ distancZs for Zxtrusion
G1 Z0.400 F71800.000
G1 X75.725 Y86.681
G1 F1800.000 Z1.00000
G1 X87.905 Y75.241 F1040.000 Z1.69560
G1 X88.365 Y74.871 Z1.72017
G1 X88.865 Y74.541 Z1.74511
G1 X89.395 Y74.261 Z1.77006
G1 X89.945 Y74.031 Z1.79488
G1 X90.225 Y73.931 Z1.80726
G1 X90.805 Y73.771 Z1.83230
G1 X92.375 Y73.501 Z1.89862
G1 X92.935 Y73.471 Z1.92196
G1 X109.165 Y73.961 Z2.59789
G1 X109.475 Y73.991 Z2.61085
G1 X110.105 Y74.101 Z2.63747
G1 X110.715 Y74.271 Z2.66383
G1 X111.795 Y74.681 Z2.71192
G1 X112.355 Y74.951 Z2.73780
G1 X112.875 Y75.271 Z2.76322
G1 X113.135 Y75.451 Z2.77638
G1 X113.615 Y75.841 Z2.80213
G1 X124.855 Y87.841 Z3.48656
G1 X125.485 Y88.631 Z3.52863
G1 X125.975 Y89.351 Z3.56488
G1 X126.385 Y90.111 Z3.60083
G1 X126.605 Y90.651 Z3.62510
G1 X126.775 Y91.201 Z3.64906
G1 X126.905 Y91.771 Z3.67340
G1 X126.975 Y92.341 Z3.69731
G1 X127.005 Y92.921 Z3.72148
G1 X126.325 Y109.851 Z4.42681
G1 X126.255 Y110.391 Z4.44947
G1 X126.145 Y110.921 Z4.47201
G1 X125.995 Y111.441 Z4.49453
G1 X125.805 Y111.951 Z4.51719
G1 X125.575 Y112.441 Z4.53972
G1 X125.165 Y113.131 Z4.57313
G1 X124.835 Y113.571 Z4.59603
G1 X124.485 Y113.971 Z4.61815
G1 X124.095 Y114.351 Z4.64082
G1 X123.885 Y114.531 Z4.65233
G1 X123.005 Y115.151 Z4.69715
G1 X122.525 Y115.401 Z4.71967
G1 X96.195 Y125.661 Z5.89600
G1 X95.515 Y125.881 Z5.92575
G1 X94.385 Y126.141 Z5.97402
G1 X91.335 Y126.551 Z6.10213
G1 X91.055 Y126.561 Z6.11379
G1 X90.775 Y126.561 Z6.12545
G1 X90.215 Y126.521 Z6.14882
G1 X89.375 Y126.371 Z6.18434
G1 X88.835 Y126.221 Z6.20767
G1 X88.305 Y126.021 Z6.23125
G1 X87.795 Y125.781 Z6.25471
G1 X87.075 Y125.341 Z6.28984
G1 X86.415 Y124.811 Z6.32507
G1 X75.155 Y112.801 Z7.01038
G1 X74.955 Y112.561 Z7.02339
G1 X74.595 Y112.041 Z7.04972
G1 X73.825 Y110.701 Z7.11405
G1 X73.695 Y110.441 Z7.12615
G1 X73.475 Y109.911 Z7.15004
G1 X73.305 Y109.361 Z7.17400
G1 X73.175 Y108.801 Z7.19794
G1 X73.095 Y108.231 Z7.22190
G1 X73.065 Y107.651 Z7.24607
G1 X73.615 Y91.111 Z7.93497
G1 X73.725 Y90.281 Z7.96982
G1 X73.785 Y90.011 Z7.98134
G1 X74.035 Y89.211 Z8.01623
G1 X74.255 Y88.701 Z8.03935
G1 X74.515 Y88.201 Z8.06281
G1 X74.815 Y87.731 Z8.08602
G1 X75.335 Y87.081 Z8.12067
G1 X75.640 Y86.766 Z8.13893