Merge branch 'experimental' of git://github.com/kenaaker/Printrun into experimental

master
Ken Aaker 2013-03-28 11:43:50 -05:00
commit 3826dd1732
10 changed files with 520 additions and 117 deletions

BIN
P-face.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

250
gcoder.py
View File

@ -16,6 +16,17 @@
import sys import sys
import re import re
import math
def deltalen(a,b):
d = object()
d.x = b.x - a.x
d.y = b.y - a.y
d.z = b.z - a.z
return math.sqrt((d.x*d.x)+(d.y*d.y)+(d.z*d.z))
class Line(object): class Line(object):
def __init__(self,l): def __init__(self,l):
@ -29,6 +40,7 @@ class Line(object):
self.raw = l.upper().lstrip() self.raw = l.upper().lstrip()
self.imperial = False self.imperial = False
self.relative = False self.relative = False
self.relative_e = False
if ";" in self.raw: if ";" in self.raw:
self.raw = self.raw.split(";")[0] self.raw = self.raw.split(";")[0]
@ -77,53 +89,55 @@ class Line(object):
return "" return ""
def _get_float(self,which): def _get_float(self,which):
return float(self.regex.findall(self.raw.split(which)[1])[0]) try:
return float(self.regex.findall(self.raw.split(which)[1])[0])
except:
return None
def _parse_coordinates(self): def _parse_coordinates(self):
if "X" in self.raw: try:
self._x = self._get_float("X") if "X" in self.raw:
self._x = self._get_float("X")
except:
pass
try:
if "Y" in self.raw:
self._y = self._get_float("Y")
except:
pass
try:
if "Z" in self.raw:
self._z = self._get_float("Z")
except:
pass
try:
if "E" in self.raw:
self.e = self._get_float("E")
except:
pass
try:
if "F" in self.raw:
self.f = self._get_float("F")
except:
pass
if "Y" in self.raw:
self._y = self._get_float("Y")
if "Z" in self.raw:
self._z = self._get_float("Z")
if "E" in self.raw:
self.e = self._get_float("E")
if "F" in self.raw:
self.f = self._get_float("F")
def is_move(self): def is_move(self):
return "G1" in self.raw or "G0" in self.raw return self.command() and ("G1" in self.raw or "G0" in self.raw)
def __str__(self):
return self.raw
class Layer(object):
def __init__(self,lines):
self.lines = lines
class GCode(object):
def __init__(self,data):
self.lines = [Line(i) for i in data]
self._preprocess()
def _preprocess(self):
#checks for G20, G21, G90 and G91, sets imperial and relative flags
imperial = False
relative = False
for line in self.lines:
if line.command() == "G20":
imperial = True
elif line.command() == "G21":
imperial = False
elif line.command() == "G90":
relative = False
elif line.command() == "G91":
relative = True
elif line.is_move():
line.imperial = imperial
line.relative = relative
def measure(self): def measure(self):
xmin = 999999999 xmin = 999999999
ymin = 999999999 ymin = 999999999
@ -132,7 +146,8 @@ class GCode(object):
ymax = -999999999 ymax = -999999999
zmax = -999999999 zmax = -999999999
relative = False relative = False
relative_e = False
current_x = 0 current_x = 0
current_y = 0 current_y = 0
current_z = 0 current_z = 0
@ -147,13 +162,13 @@ class GCode(object):
x = line.x x = line.x
y = line.y y = line.y
z = line.z z = line.z
if line.relative: if line.relative:
x = current_x + (x or 0) x = current_x + (x or 0)
y = current_y + (y or 0) y = current_y + (y or 0)
z = current_z + (z or 0) z = current_z + (z or 0)
if x and line.e: if x and line.e:
if x < xmin: if x < xmin:
xmin = x xmin = x
@ -169,22 +184,137 @@ class GCode(object):
zmin = z zmin = z
if z > zmax: if z > zmax:
zmax = z zmax = z
current_x = x or current_x current_x = x or current_x
current_y = y or current_y current_y = y or current_y
current_z = z or current_z current_z = z or current_z
self.xmin = xmin return ( (xmin,xmax),(ymin,ymax),(zmin,zmax) )
self.ymin = ymin
self.zmin = zmin
self.xmax = xmax
self.ymax = ymax
self.zmax = zmax
self.width = xmax-xmin
self.depth = ymax-ymin
self.height = zmax-zmin
class GCode(object):
def __init__(self,data):
self.lines = [Line(i) for i in data]
self._preprocess()
self._create_layers()
def _preprocess(self):
#checks for G20, G21, G90 and G91, sets imperial and relative flags
imperial = False
relative = False
relative_e = False
for line in self.lines:
if line.command() == "G20":
imperial = True
elif line.command() == "G21":
imperial = False
elif line.command() == "G90":
relative = False
relative_e = False
elif line.command() == "G91":
relative = True
relative_e = True
elif line.command() == "M82":
relative_e = False
elif line.command() == "M83":
relative_e = True
elif line.is_move():
line.imperial = imperial
line.relative = relative
line.relative_e = relative_e
def _create_layers(self):
self.layers = []
prev_z = None
cur_z = 0
cur_lines = []
layer_index = []
temp_layers = {}
for line in self.lines:
if line.command() == "G92" and line.z != None:
cur_z = line.z
elif line.is_move():
if line.z != None:
if line.relative:
cur_z += line.z
else:
cur_z = line.z
if cur_z != prev_z:
old_lines = temp_layers.pop(prev_z,[])
old_lines += cur_lines
temp_layers[prev_z] = old_lines
if not prev_z in layer_index:
layer_index.append(prev_z)
cur_lines = []
cur_lines.append(line)
prev_z = cur_z
old_lines = temp_layers.pop(prev_z,[])
old_lines += cur_lines
temp_layers[prev_z] = old_lines
if not prev_z in layer_index:
layer_index.append(prev_z)
layer_index.sort()
for idx in layer_index:
cur_lines = temp_layers[idx]
has_movement = False
for l in cur_lines:
if l.is_move() and l.e != None:
has_movement = True
break
if has_movement:
self.layers.append(Layer(cur_lines))
def num_layers(self):
return len(self.layers)
def measure(self):
xmin = 999999999
ymin = 999999999
zmin = 0
xmax = -999999999
ymax = -999999999
zmax = -999999999
for l in self.layers:
xd,yd,zd = l.measure()
if xd[0] < xmin:
xmin = xd[0]
if xd[1] > xmax:
xmax = xd[1]
if yd[0] < ymin:
ymin = yd[0]
if yd[1] > ymax:
ymax = yd[1]
if zd[0] < zmin:
zmin = zd[0]
if zd[1] > zmax:
zmax = zd[1]
self.xmin = xmin
self.xmax = xmax
self.ymin = ymin
self.ymax = ymax
self.zmin = zmin
self.zmax = zmax
self.width = xmax - xmin
self.depth = ymax - ymin
self.height = zmax - zmin
def filament_length(self): def filament_length(self):
total_e = 0 total_e = 0
@ -196,7 +326,7 @@ class GCode(object):
total_e += cur_e total_e += cur_e
cur_e = line.e cur_e = line.e
elif line.is_move() and line.e: elif line.is_move() and line.e:
if line.relative: if line.relative_e:
cur_e += line.e cur_e += line.e
else: else:
cur_e = line.e cur_e = line.e
@ -210,6 +340,8 @@ def main():
print "usage: %s filename.gcode" % sys.argv[0] print "usage: %s filename.gcode" % sys.argv[0]
return return
# d = [i.replace("\n","") for i in open(sys.argv[1])]
# gcode = GCode(d)
gcode = GCode(list(open(sys.argv[1]))) gcode = GCode(list(open(sys.argv[1])))
gcode.measure() gcode.measure()
@ -219,6 +351,8 @@ def main():
print "\tY: %0.02f - %0.02f (%0.02f)" % (gcode.ymin,gcode.ymax,gcode.depth) print "\tY: %0.02f - %0.02f (%0.02f)" % (gcode.ymin,gcode.ymax,gcode.depth)
print "\tZ: %0.02f - %0.02f (%0.02f)" % (gcode.zmin,gcode.zmax,gcode.height) print "\tZ: %0.02f - %0.02f (%0.02f)" % (gcode.zmin,gcode.zmax,gcode.height)
print "Filament used: %0.02fmm" % gcode.filament_length() print "Filament used: %0.02fmm" % gcode.filament_length()
print "Number of layers: %d" % gcode.num_layers()
if __name__ == '__main__': if __name__ == '__main__':
main() main()

BIN
plater.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -222,6 +222,7 @@ class printcore():
def pause(self): def pause(self):
"""Pauses the print, saving the current position. """Pauses the print, saving the current position.
""" """
if not self.printing: return False
self.paused = True self.paused = True
self.printing = False self.printing = False
self.print_thread.join() self.print_thread.join()
@ -230,6 +231,7 @@ class printcore():
def resume(self): def resume(self):
"""Resumes a paused print. """Resumes a paused print.
""" """
if not self.paused: return False
self.paused = False self.paused = False
self.printing = True self.printing = True
self.print_thread = Thread(target = self._print) self.print_thread = Thread(target = self._print)
@ -287,6 +289,8 @@ class printcore():
self.sentlines = {} self.sentlines = {}
self.log = [] self.log = []
self.sent = [] self.sent = []
self.print_thread.join()
self.print_thread = None
if self.endcb: if self.endcb:
#callback for printing done #callback for printing done
try: self.endcb() try: self.endcb()

View File

@ -223,7 +223,7 @@ class MainToolbar(wx.BoxSizer):
root.serialport = wx.ComboBox(root.panel, -1, root.serialport = wx.ComboBox(root.panel, -1,
choices = root.scanserial(), choices = root.scanserial(),
style = wx.CB_DROPDOWN, size = (100, 25)) style = wx.CB_DROPDOWN, size = (150, 25))
root.serialport.SetToolTip(wx.ToolTip("Select Port Printer is connected to")) root.serialport.SetToolTip(wx.ToolTip("Select Port Printer is connected to"))
root.rescanports() root.rescanports()
self.Add(root.serialport) self.Add(root.serialport)

View File

@ -23,7 +23,7 @@ from printrun.printrun_utils import configfile, imagefile, sharedfile
users = {} users = {}
def PrintHeader(): def PrintHeader():
return '<html>\n<head>\n<title>Pronterface-Web</title>\n<link rel = "stylesheet" type = "text/css" href = "/css/style.css" type = "text/css"></link>\n</head>\n<body>\n' return '<html>\n<head>\n<title>Pronterface-Web</title>\n<link rel = "stylesheet" type = "text/css" href = "/css/style.css" type = "text/css"></link>\n<script src="/js/asyncCommand.js"></script>\n</head>\n<body>\n'
def PrintMenu(): def PrintMenu():
return '<div id = "mainmenu"><ul><li><a href = "/">home</a></li><li><a href = "/settings">settings</a></li><li><a href = "/console">console</a></li><li><a href = "/status">status (XML)</a></li></ul></div>' return '<div id = "mainmenu"><ul><li><a href = "/">home</a></li><li><a href = "/settings">settings</a></li><li><a href = "/console">console</a></li><li><a href = "/status">status (XML)</a></li></ul></div>'
@ -284,14 +284,14 @@ class WebInterface(object):
pageText = PrintHeader()+self.name+PrintMenu() pageText = PrintHeader()+self.name+PrintMenu()
pageText+="<div id='content'>\n" pageText+="<div id='content'>\n"
pageText+="<div id='controls'>\n" pageText+="<div id='controls'>\n"
pageText+="<ul><li><a href='/connect'>Connect</a></li>\n" pageText+="<ul><li><a class='command' href='/connect'>Connect</a></li>\n"
pageText+="<li><a href='/disconnect'>Disconnect</a></li>\n" pageText+="<li><a class='command' href='/disconnect'>Disconnect</a></li>\n"
pageText+="<li><a href='/reset'>Reset</a></li>\n" pageText+="<li><a class='command' href='/reset'>Reset</a></li>\n"
pageText+="<li><a href='/printbutton'>Print</a></li>\n" pageText+="<li><a class='command' href='/printbutton'>Print</a></li>\n"
pageText+="<li><a href='/pausebutton'>Pause</a></li>\n" pageText+="<li><a class='command' href='/pausebutton'>Pause</a></li>\n"
for i in gPronterPtr.cpbuttons: for i in gPronterPtr.cpbuttons:
pageText+="<li><a href='/custom/button/"+i[1]+"'>"+i[0]+"</a></li>\n" pageText+="<li><a class='command' href='/custom/button/"+i.command+"'>"+i.label+"</a></li>\n"
#for i in gPronterPtr.custombuttons: #for i in gPronterPtr.custombuttons:
# print(str(i)); # print(str(i));
@ -303,38 +303,38 @@ class WebInterface(object):
pageText+="<img src='/images/control_xy.png' usemap='#xymap'/>" pageText+="<img src='/images/control_xy.png' usemap='#xymap'/>"
pageText+='<map name = "xymap">' pageText+='<map name = "xymap">'
pageText+='<area shape = "rect" coords = "8, 5, 51, 48" href = "/home/axis/x" alt = "X Home" title = "X Home" />' pageText+='<area shape = "rect" class="command" coords = "8, 5, 51, 48" href = "/home/axis/x" alt = "X Home" title = "X Home" />'
pageText+='<area shape = "rect" coords = "195, 6, 236, 46" href = "/home/axis/y" alt = "Y Home" title = "Y Home" />' pageText+='<area shape = "rect" class="command" coords = "195, 6, 236, 46" href = "/home/axis/y" alt = "Y Home" title = "Y Home" />'
pageText+='<area shape = "rect" coords = "7, 192, 48, 232" href = "/home/axis/all" alt = "All Home" title = "All Home" />' pageText+='<area shape = "rect" class="command" coords = "7, 192, 48, 232" href = "/home/axis/all" alt = "All Home" title = "All Home" />'
pageText+='<area shape = "rect" coords = "194, 192, 235, 232" href = "/home/axis/z" alt = "Z Home" title = "Z Home" />' pageText+='<area shape = "rect" class="command" coords = "194, 192, 235, 232" href = "/home/axis/z" alt = "Z Home" title = "Z Home" />'
pageText+='<area shape = "rect" coords = "62, 7, 185, 34" href = "/move/axis/y/100" alt = "Y 100" title = "Y 100" />' pageText+='<area shape = "rect" class="command" coords = "62, 7, 185, 34" href = "/move/axis/y/100" alt = "Y 100" title = "Y 100" />'
pageText+='<area shape = "rect" coords = "68, 34, 175, 61" href = "/move/axis/y/10" alt = "Y 10" title = "Y 10" />' pageText+='<area shape = "rect" class="command" coords = "68, 34, 175, 61" href = "/move/axis/y/10" alt = "Y 10" title = "Y 10" />'
pageText+='<area shape = "rect" coords = "80, 60, 163, 84" href = "/move/axis/y/1" alt = "Y 1" title = "Y 1" />' pageText+='<area shape = "rect" class="command" coords = "80, 60, 163, 84" href = "/move/axis/y/1" alt = "Y 1" title = "Y 1" />'
pageText+='<area shape = "rect" coords = "106, 83, 138, 107" href = "/move/axis/y/.1" alt = "Y .1" title = "Y .1" />' pageText+='<area shape = "rect" class="command" coords = "106, 83, 138, 107" href = "/move/axis/y/.1" alt = "Y .1" title = "Y .1" />'
pageText+='<area shape = "rect" coords = "110, 135, 142, 159" href = "/move/axis/y/-.1" alt = "Y -.1" title = "Y -.1" />' pageText+='<area shape = "rect" class="command" coords = "110, 135, 142, 159" href = "/move/axis/y/-.1" alt = "Y -.1" title = "Y -.1" />'
pageText+='<area shape = "rect" coords = "81, 157, 169, 181" href = "/move/axis/y/-1" alt = "Y -1" title = "Y -1" />' pageText+='<area shape = "rect" class="command" coords = "81, 157, 169, 181" href = "/move/axis/y/-1" alt = "Y -1" title = "Y -1" />'
pageText+='<area shape = "rect" coords = "69, 180, 178, 206" href = "/move/axis/y/-10" alt = "Y -10" title = "Y -10" />' pageText+='<area shape = "rect" class="command" coords = "69, 180, 178, 206" href = "/move/axis/y/-10" alt = "Y -10" title = "Y -10" />'
pageText+='<area shape = "rect" coords = "60, 205, 186, 231" href = "/move/axis/y/-100" alt = "Y -100" title = "Y -100" />' pageText+='<area shape = "rect" class="command" coords = "60, 205, 186, 231" href = "/move/axis/y/-100" alt = "Y -100" title = "Y -100" />'
pageText+='<area shape = "rect" coords = "11, 53, 37, 179" href = "/move/axis/x/-100" alt = "X -100" title = "X -100" />' pageText+='<area shape = "rect" class="command" coords = "11, 53, 37, 179" href = "/move/axis/x/-100" alt = "X -100" title = "X -100" />'
pageText+='<area shape = "rect" coords = "210, 59, 236, 185" href = "/move/axis/x/100" alt = "X 100" title = "X 100" />' pageText+='<area shape = "rect" class="command" coords = "210, 59, 236, 185" href = "/move/axis/x/100" alt = "X 100" title = "X 100" />'
pageText+='<area shape = "rect" coords = "38, 60, 64, 172" href = "/move/axis/x/-10" alt = "X -10" title = "X -10" />' pageText+='<area shape = "rect" class="command" coords = "38, 60, 64, 172" href = "/move/axis/x/-10" alt = "X -10" title = "X -10" />'
pageText+='<area shape = "rect" coords = "185, 66, 211, 178" href = "/move/axis/x/10" alt = "X 10" title = "X 10" />' pageText+='<area shape = "rect" class="command" coords = "185, 66, 211, 178" href = "/move/axis/x/10" alt = "X 10" title = "X 10" />'
pageText+='<area shape = "rect" coords = "62, 84, 83, 157" href = "/move/axis/x/-1" alt = "X -1" title = "X -1" />' pageText+='<area shape = "rect" class="command" coords = "62, 84, 83, 157" href = "/move/axis/x/-1" alt = "X -1" title = "X -1" />'
pageText+='<area shape = "rect" coords = "163, 87, 187, 160" href = "/move/axis/x/1" alt = "X 1" title = "X 1" />' pageText+='<area shape = "rect" class="command" coords = "163, 87, 187, 160" href = "/move/axis/x/1" alt = "X 1" title = "X 1" />'
pageText+='<area shape = "rect" coords = "82, 104, 110, 139" href = "/move/axis/x/-.1" alt = "X -.1" title = "X -.1" />' pageText+='<area shape = "rect" class="command" coords = "82, 104, 110, 139" href = "/move/axis/x/-.1" alt = "X -.1" title = "X -.1" />'
pageText+='<area shape = "rect" coords = "137, 105, 165, 140" href = "/move/axis/x/.1" alt = "X .1" title = "X .1" />' pageText+='<area shape = "rect" class="command" coords = "137, 105, 165, 140" href = "/move/axis/x/.1" alt = "X .1" title = "X .1" />'
pageText+="</map>" pageText+="</map>"
pageText+="</div>\n" #endxy pageText+="</div>\n" #endxy
pageText+="<div id='control_z'>" pageText+="<div id='control_z'>"
pageText+="<img src='/images/control_z.png' usemap='#zmap'/>" pageText+="<img src='/images/control_z.png' usemap='#zmap'/>"
pageText+='<map name = "zmap">' pageText+='<map name = "zmap">'
pageText+='<area shape = "rect" coords = "4, 35, 54, 64" href = "/move/axis/z/10" alt = "Z 10" title = "Z 10" />' pageText+='<area shape = "rect" class="command" coords = "4, 35, 54, 64" href = "/move/axis/z/10" alt = "Z 10" title = "Z 10" />'
pageText+='<area shape = "rect" coords = "4, 60, 54, 89" href = "/move/axis/z/1" alt = "Z 1" title = "Z 1" />' pageText+='<area shape = "rect" class="command" coords = "4, 60, 54, 89" href = "/move/axis/z/1" alt = "Z 1" title = "Z 1" />'
pageText+='<area shape = "rect" coords = "4, 87, 54, 116" href = "/move/axis/z/.1" alt = "Z .1" title = "Z .1" />' pageText+='<area shape = "rect" class="command" coords = "4, 87, 54, 116" href = "/move/axis/z/.1" alt = "Z .1" title = "Z .1" />'
pageText+='<area shape = "rect" coords = "4, 121, 54, 150" href = "/move/axis/z/-.1" alt = "Z -.1" title = "Z -.1" />' pageText+='<area shape = "rect" class="command" coords = "4, 121, 54, 150" href = "/move/axis/z/-.1" alt = "Z -.1" title = "Z -.1" />'
pageText+='<area shape = "rect" coords = "4, 147, 54, 176" href = "/move/axis/z/-1" alt = "Z -1" title = "Z -1" />' pageText+='<area shape = "rect" class="command" coords = "4, 147, 54, 176" href = "/move/axis/z/-1" alt = "Z -1" title = "Z -1" />'
pageText+='<area shape = "rect" coords = "4, 173, 54, 202" href = "/move/axis/z/-10" alt = "Z -10" title = "Z -10" />' pageText+='<area shape = "rect" class="command" coords = "4, 173, 54, 202" href = "/move/axis/z/-10" alt = "Z -10" title = "Z -10" />'
pageText+="</map>" pageText+="</map>"
#TODO Map Z Moves #TODO Map Z Moves
pageText+="</div>\n" #endz pageText+="</div>\n" #endz
@ -374,11 +374,14 @@ def KillWebInterfaceThread():
cherrypy.engine.exit() cherrypy.engine.exit()
def StartWebInterfaceThread(webInterface): def StartWebInterfaceThread(webInterface):
current_dir = os.path.dirname(os.path.abspath(__file__)) current_dir = os.path.dirname(os.path.abspath(__file__))
cherrypy.config.update({'engine.autoreload_on':False}) cherrypy.config.update({'engine.autoreload_on':False})
cherrypy.config.update(configfile(webInterface.pface.web_config or "http.config")) cherrypy.config.update(configfile(webInterface.pface.web_config or "http.config"))
conf = {'/css/style.css': {'tools.staticfile.on': True, conf = {'/css/style.css': {'tools.staticfile.on': True,
'tools.staticfile.filename': sharedfile('css/style.css'), 'tools.staticfile.filename': sharedfile('web/css/style.css'),
},
'/js/asyncCommand.js': {'tools.staticfile.on': True,
'tools.staticfile.filename': sharedfile('web/js/asyncCommand.js'),
}, },
'/images/control_xy.png': {'tools.staticfile.on': True, '/images/control_xy.png': {'tools.staticfile.on': True,
'tools.staticfile.filename': imagefile('control_xy.png'), 'tools.staticfile.filename': imagefile('control_xy.png'),

BIN
pronsole.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -131,6 +131,14 @@ def estimate_duration(g):
#print "Total Duration: " #, time.strftime('%H:%M:%S', time.gmtime(totalduration)) #print "Total Duration: " #, time.strftime('%H:%M:%S', time.gmtime(totalduration))
return "{0:d} layers, ".format(int(layercount)) + str(datetime.timedelta(seconds = int(totalduration))) return "{0:d} layers, ".format(int(layercount)) + str(datetime.timedelta(seconds = int(totalduration)))
def confirm():
y_or_n = raw_input("y/n: ")
if y_or_n == "y":
return True
elif y_or_n != "n":
return confirm()
return False
class Settings: class Settings:
#def _temperature_alias(self): return {"pla":210, "abs":230, "off":0} #def _temperature_alias(self): return {"pla":210, "abs":230, "off":0}
#def _temperature_validate(self, v): #def _temperature_validate(self, v):
@ -183,15 +191,46 @@ class Settings:
def _all_settings(self): def _all_settings(self):
return dict([(k, getattr(self, k)) for k in self.__dict__.keys() if not k.startswith("_")]) return dict([(k, getattr(self, k)) for k in self.__dict__.keys() if not k.startswith("_")])
class Status:
def __init__(self):
self.extruder_temp = 0
self.extruder_temp_target = 0
self.bed_temp = 0
self.bed_temp_target = 0
self.print_job = None
self.print_job_progress = 1.0
def update_tempreading(self, tempstr):
r = tempstr.split()
# eg. r = ["ok", "T:20.5", "/0.0", "B:0.0", "/0.0", "@:0"]
if len(r) == 6:
self.extruder_temp = float(r[1][2:])
self.extruder_temp_target = float(r[2][1:])
self.bed_temp = float(r[3][2:])
self.bed_temp_target = float(r[4][1:])
@property
def bed_enabled(self):
return self.bed_temp != 0
@property
def extruder_enabled(self):
return self.extruder_temp != 0
class pronsole(cmd.Cmd): class pronsole(cmd.Cmd):
def __init__(self): def __init__(self):
cmd.Cmd.__init__(self) cmd.Cmd.__init__(self)
if not READLINE: if not READLINE:
self.completekey = None self.completekey = None
self.status = Status()
self.dynamic_temp = False
self.p = printcore.printcore() self.p = printcore.printcore()
self.p.recvcb = self.recvcb self.p.recvcb = self.recvcb
self.recvlisteners = [] self.recvlisteners = []
self.prompt = "PC>" self.in_macro = False
self.p.onlinecb = self.online self.p.onlinecb = self.online
self.f = None self.f = None
self.listing = 0 self.listing = 0
@ -230,6 +269,55 @@ class pronsole(cmd.Cmd):
self.webrequested = False self.webrequested = False
self.web_config = None self.web_config = None
self.web_auth_config = None self.web_auth_config = None
self.promptstrs = {"offline" : "%(bold)suninitialized>%(normal)s ",
"fallback" : "%(bold)sPC>%(normal)s ",
"macro" : "%(bold)s..>%(normal)s ",
"online" : "%(bold)sT:%(extruder_temp_fancy)s %(progress_fancy)s >%(normal)s "}
def promptf(self):
"""A function to generate prompts so that we can do dynamic prompts. """
if self.in_macro:
promptstr = self.promptstrs["macro"]
elif not self.p.online:
promptstr = self.promptstrs["offline"]
elif self.status.extruder_enabled:
promptstr = self.promptstrs["online"]
else:
promptstr = self.promptstrs["fallback"]
if not "%" in promptstr:
return promptstr
else:
specials = {}
specials["extruder_temp"] = str(int(self.status.extruder_temp))
specials["extruder_temp_target"] = str(int(self.status.extruder_temp_target))
if self.status.extruder_temp_target == 0:
specials["extruder_temp_fancy"] = str(int(self.status.extruder_temp))
else:
specials["extruder_temp_fancy"] = "%s/%s" % (str(int(self.status.extruder_temp)), str(int(self.status.extruder_temp_target)))
if self.p.printing:
progress = int(1000*float(self.p.queueindex)/len(self.p.mainqueue)) / 10
elif self.sdprinting:
progress = self.percentdone
else:
progress = 0.0
specials["progress"] = str(progress)
if self.p.printing or self.sdprinting:
specials["progress_fancy"] = str(progress) +"%"
else:
specials["progress_fancy"] = "?%"
specials["bold"] = "\033[01m"
specials["normal"] = "\033[00m"
return promptstr % specials
def postcmd(self, stop, line):
""" A hook we override to generate prompts after
each command is executed, for the next prompt.
We also use it to send M105 commands so that
temp info gets updated for the prompt."""
if self.p.online and self.dynamic_temp:
self.p.send_now("M105")
self.prompt = self.promptf()
return stop
def set_temp_preset(self, key, value): def set_temp_preset(self, key, value):
if not key.startswith("bed"): if not key.startswith("bed"):
@ -257,8 +345,8 @@ class pronsole(cmd.Cmd):
return baselist+glob.glob('/dev/ttyUSB*') + glob.glob('/dev/ttyACM*') +glob.glob("/dev/tty.*")+glob.glob("/dev/cu.*")+glob.glob("/dev/rfcomm*") return baselist+glob.glob('/dev/ttyUSB*') + glob.glob('/dev/ttyACM*') +glob.glob("/dev/tty.*")+glob.glob("/dev/cu.*")+glob.glob("/dev/rfcomm*")
def online(self): def online(self):
print "Printer is now online" print "\rPrinter is now online"
sys.stdout.write(self.prompt) sys.stdout.write(self.promptf())
sys.stdout.flush() sys.stdout.flush()
def help_help(self, l): def help_help(self, l):
@ -290,7 +378,8 @@ class pronsole(cmd.Cmd):
def end_macro(self): def end_macro(self):
if self.__dict__.has_key("onecmd"): del self.onecmd # remove override if self.__dict__.has_key("onecmd"): del self.onecmd # remove override
self.prompt = "PC>" self.in_macro = False
self.prompt = self.promptf()
if self.cur_macro_def!="": if self.cur_macro_def!="":
self.macros[self.cur_macro_name] = self.cur_macro_def self.macros[self.cur_macro_name] = self.cur_macro_def
macro = self.compile_macro(self.cur_macro_name, self.cur_macro_def) macro = self.compile_macro(self.cur_macro_name, self.cur_macro_def)
@ -342,7 +431,8 @@ class pronsole(cmd.Cmd):
self.cur_macro_name = macro_name self.cur_macro_name = macro_name
self.cur_macro_def = "" self.cur_macro_def = ""
self.onecmd = self.hook_macro # override onecmd temporarily self.onecmd = self.hook_macro # override onecmd temporarily
self.prompt = "..>" self.in_macro = False
self.prompt = self.promptf()
def delete_macro(self, macro_name): def delete_macro(self, macro_name):
if macro_name in self.macros.keys(): if macro_name in self.macros.keys():
@ -520,6 +610,7 @@ class pronsole(cmd.Cmd):
def preloop(self): def preloop(self):
print "Welcome to the printer console! Type \"help\" for a list of available commands." print "Welcome to the printer console! Type \"help\" for a list of available commands."
self.prompt = self.promptf()
cmd.Cmd.preloop(self) cmd.Cmd.preloop(self)
def do_connect(self, l): def do_connect(self, l):
@ -813,10 +904,13 @@ class pronsole(cmd.Cmd):
def recvcb(self, l): def recvcb(self, l):
if "T:" in l: if "T:" in l:
self.tempreadings = l self.tempreadings = l
self.status.update_tempreading(l)
tstring = l.rstrip() tstring = l.rstrip()
if(tstring!="ok" and not tstring.startswith("ok T") and not tstring.startswith("T:") and not self.listing and not self.monitoring): if(tstring!="ok" and not tstring.startswith("ok T") and not tstring.startswith("T:") and not self.listing and not self.monitoring):
print tstring if tstring[:5] == "echo:":
sys.stdout.write(self.prompt) tstring = tstring[5:].lstrip()
print "\r" + tstring.ljust(15)
sys.stdout.write(self.promptf())
sys.stdout.flush() sys.stdout.flush()
for i in self.recvlisteners: for i in self.recvlisteners:
i(l) i(l)
@ -848,16 +942,17 @@ class pronsole(cmd.Cmd):
def help_help(self): def help_help(self):
self.do_help("") self.do_help("")
def tempcb(self, l):
if "T:" in l:
print l.replace("\r", "").replace("T", "Hotend").replace("B", "Bed").replace("\n", "").replace("ok ", "")
def do_gettemp(self, l): def do_gettemp(self, l):
if "dynamic" in l:
self.dynamic_temp = True
if self.p.online: if self.p.online:
self.recvlisteners+=[self.tempcb]
self.p.send_now("M105") self.p.send_now("M105")
time.sleep(0.75) time.sleep(0.75)
self.recvlisteners.remove(self.tempcb) if not self.status.bed_enabled:
print "Hotend: %s/%s" % (self.status.extruder_temp, self.status.extruder_temp_target)
else:
print "Hotend: %s/%s" % (self.status.extruder_temp, self.status.extruder_temp_target)
print "Bed: %s/%s" % (self.status.bed_temp, self.status.bed_temp_target)
def help_gettemp(self): def help_gettemp(self):
print "Read the extruder and bed temperature." print "Read the extruder and bed temperature."
@ -869,6 +964,10 @@ class pronsole(cmd.Cmd):
l = l.replace(i, self.temps[i]) l = l.replace(i, self.temps[i])
f = float(l) f = float(l)
if f>=0: if f>=0:
if f > 250:
print f, " is a high temperature to set your extruder to. Are you sure you want to do that?"
if not confirm():
return
if self.p.online: if self.p.online:
self.p.send_now("M104 S"+l) self.p.send_now("M104 S"+l)
print "Setting hotend temperature to ", f, " degrees Celsius." print "Setting hotend temperature to ", f, " degrees Celsius."
@ -1045,9 +1144,22 @@ class pronsole(cmd.Cmd):
print "reverse -5 - EXTRUDES 5mm of filament at 300mm/min (5mm/s)" print "reverse -5 - EXTRUDES 5mm of filament at 300mm/min (5mm/s)"
def do_exit(self, l): def do_exit(self, l):
if self.status.extruder_temp_target != 0:
print "Setting extruder temp to 0"
self.p.send_now("M104 S0.0")
if self.status.bed_enabled:
if self.status.bed_temp_taret != 0:
print "Setting bed temp to 0"
self.p.send_now("M140 S0.0")
print "Disconnecting from printer..." print "Disconnecting from printer..."
self.p.disconnect() print self.p.printing
if self.p.printing:
print "Are you sure you want to exit while printing?"
print "(this will terminate the print)."
if not confirm():
return False
print "Exiting program. Goodbye!" print "Exiting program. Goodbye!"
self.p.disconnect()
return True return True
def help_exit(self): def help_exit(self):
@ -1058,6 +1170,9 @@ class pronsole(cmd.Cmd):
if not self.p.online: if not self.p.online:
print "Printer is not online. Please connect first." print "Printer is not online. Please connect first."
return return
if not (self.p.printing or self.sdprinting):
print "Printer not printing. Please print something before monitoring."
return
print "Monitoring printer, use ^C to interrupt." print "Monitoring printer, use ^C to interrupt."
if len(l): if len(l):
try: try:
@ -1066,22 +1181,27 @@ class pronsole(cmd.Cmd):
print "Invalid period given." print "Invalid period given."
print "Updating values every %f seconds."%(interval,) print "Updating values every %f seconds."%(interval,)
self.monitoring = 1 self.monitoring = 1
prev_msg_len = 0
try: try:
while(1): while True:
self.p.send_now("M105") self.p.send_now("M105")
if(self.sdprinting): if(self.sdprinting):
self.p.send_now("M27") self.p.send_now("M27")
time.sleep(interval) time.sleep(interval)
#print (self.tempreadings.replace("\r", "").replace("T", "Hotend").replace("B", "Bed").replace("\n", "").replace("ok ", "")) #print (self.tempreadings.replace("\r", "").replace("T", "Hotend").replace("B", "Bed").replace("\n", "").replace("ok ", ""))
if(self.p.printing): if self.p.printing:
print "Print progress: ", 100*float(self.p.queueindex)/len(self.p.mainqueue), "%" preface = "Print progress: "
progress = 100*float(self.p.queueindex)/len(self.p.mainqueue)
if(self.sdprinting): elif self.sdprinting:
print "SD print progress: ", self.percentdone, "%" preface = "Print progress: "
progress = self.percentdone
except: progress = int(progress*10)/10.0 #limit precision
prev_msg = preface + str(progress) + "%"
sys.stdout.write("\r" + prev_msg.ljust(prev_msg_len))
sys.stdout.flush()
prev_msg_len = len(prev_msg)
except KeyboardInterrupt:
print "Done monitoring." print "Done monitoring."
pass
self.monitoring = 0 self.monitoring = 0
def help_monitor(self): def help_monitor(self):
@ -1193,6 +1313,69 @@ class pronsole(cmd.Cmd):
self.onecmd(a) self.onecmd(a)
self.processing_args = False self.processing_args = False
# We replace this function, defined in cmd.py .
# It's default behavior with reagrds to Ctr-C
# and Ctr-D doesn't make much sense...
def cmdloop(self, intro=None):
"""Repeatedly issue a prompt, accept input, parse an initial prefix
off the received input, and dispatch to action methods, passing them
the remainder of the line as argument.
"""
self.preloop()
if self.use_rawinput and self.completekey:
try:
import readline
self.old_completer = readline.get_completer()
readline.set_completer(self.complete)
readline.parse_and_bind(self.completekey+": complete")
except ImportError:
pass
try:
if intro is not None:
self.intro = intro
if self.intro:
self.stdout.write(str(self.intro)+"\n")
stop = None
while not stop:
if self.cmdqueue:
line = self.cmdqueue.pop(0)
else:
if self.use_rawinput:
try:
line = raw_input(self.prompt)
except EOFError:
print ""
should_exit = self.do_exit("")
if should_exit:
exit()
except KeyboardInterrupt:
print ""
line = ""
else:
self.stdout.write(self.prompt)
self.stdout.flush()
line = self.stdin.readline()
if not len(line):
line = ""
else:
line = line.rstrip('\r\n')
line = self.precmd(line)
stop = self.onecmd(line)
stop = self.postcmd(stop, line)
self.postloop()
finally:
if self.use_rawinput and self.completekey:
try:
import readline
readline.set_completer(self.old_completer)
except ImportError:
pass
if __name__ == "__main__": if __name__ == "__main__":
interp = pronsole() interp = pronsole()

79
web/js/asyncCommand.js Normal file
View File

@ -0,0 +1,79 @@
function pronterfaceWebInterface_setup(){
pronterfaceWebInterface_attachAsync();
}
function pronterfaceWebInterface_attachAsync(){
var list = [];
if(document.getElementsByClassName){
list = document.getElementsByClassName('command');
}else if(document.getElementsByTagName){
list = document.getElementsByTagName('a');
list.concat( document.getElementsByTagName('area') );
//TODO filter list via checking the className attributes
}else{
console && console.error && console.error('unable to gather list of elements');
return false;
}
for(var i=0; i < list.length; i++){
list[i].addEventListener && list[i].addEventListener( 'click', function(e){return pronterfaceWebInterface_asyncCommand(null, e);}, true );
list[i].attachEvent && list[i].attachEvent( 'onclick', function(e){return pronterfaceWebInterface_asyncCommand(null, e);} );
}
return true;
}
function pronterfaceWebInterface_asyncCommand( urlOrElement, event ){
if( ! urlOrElement && event.target)
urlOrElement = event.target;
var url = null;
if( typeof urlOrElement == 'string' ){
url = urlOrElement;
}else{
url = urlOrElement&&urlOrElement.href;
}
if( typeof url != 'string' ){
console && console.error && console.error('url not a string', urlOrElement, url);
return true;
}
var httpRequest;
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
httpRequest = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE 8 and older
httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
if( ! httpRequest ){
alert('no AJAX available?');
// follow link
return true;
}
//onreadystatechange
//onerror
httpRequest.open( 'GET', url, true);
httpRequest.send(null);
// don't follow link
if( event ){
event.stopImmediatePropagation && event.stopImmediatePropagation();
event.defaultPrevented = true;
event.preventDefault && event.preventDefault();
}
return false;
}
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", pronterfaceWebInterface_setup, false);
} else if (document.attachEvent) {
document.attachEvent("onreadystatechange", pronterfaceWebInterface_setup);
} else {
document.onload = pronterfaceWebInterface_setup;
}