commit
8c24401ddb
|
@ -2,3 +2,4 @@
|
||||||
.pronsolerc
|
.pronsolerc
|
||||||
*.swp
|
*.swp
|
||||||
*.bak
|
*.bak
|
||||||
|
uploads
|
||||||
|
|
23
README.md
23
README.md
|
@ -3,7 +3,6 @@ Printrun consists of printcore, pronsole and pronterface, and a small collection
|
||||||
* printcore.py is a library that makes writing reprap hosts easy
|
* printcore.py is a library that makes writing reprap hosts easy
|
||||||
* pronsole.py is an interactive command-line host software with tabcompletion goodness
|
* pronsole.py is an interactive command-line host software with tabcompletion goodness
|
||||||
* pronterface.py is a graphical host software with the same functionality as pronsole
|
* pronterface.py is a graphical host software with the same functionality as pronsole
|
||||||
* webinterface.py is a browser-usable remote control function for Pronterface
|
|
||||||
|
|
||||||
# GETTING PRINTRUN
|
# GETTING PRINTRUN
|
||||||
|
|
||||||
|
@ -51,23 +50,19 @@ The command box recognizes all pronsole commands, but has no tabcompletion.
|
||||||
If you want to load stl files, you need to install a slicing program such as Slic3r and add its path to the settings.
|
If you want to load stl files, you need to install a slicing program such as Slic3r and add its path to the settings.
|
||||||
See the Slic3r readme for more details on integration.
|
See the Slic3r readme for more details on integration.
|
||||||
|
|
||||||
# Using the browser interface
|
|
||||||
|
|
||||||
To run the web interface, install Cherrypy and run Pronterface as described above.
|
# USING PRONSERVE
|
||||||
The www server will start on the port/address you have chosen.
|
|
||||||
|
|
||||||
## Webinterface Dependencies
|
Pronserve runs a server for remote controlling your 3D printer over your network. To use pronserve you need:
|
||||||
|
|
||||||
Cherrypy is required for the web interface. Download and install it by opening a
|
* python (ideally 2.6.x or 2.7.x),
|
||||||
command prompt in its directory and running python setup.py install.
|
* pyserial (or python-serial on ubuntu/debian) and
|
||||||
|
* tornado
|
||||||
|
* D1plo1d's py-mdns fork (https://github.com/D1plo1d/py-mdns)
|
||||||
|
* pybonjour
|
||||||
|
* bonjour for windows (Windows ONLY)
|
||||||
|
|
||||||
## Webinterface Configuration
|
When you're done setting up Printrun, you can start `pronserve.py` in the directory you unpacked it. Once the server starts you can verify it's working by going to http://localhost:8888 in your web browser.
|
||||||
* The Web interface port / ip is configurable in http.config
|
|
||||||
* The Default User / Password can be set in auth.config
|
|
||||||
|
|
||||||
## Webinterface Styling
|
|
||||||
* css/style.css can be modified to change the style of the Web Interface.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# USING PRONSOLE
|
# USING PRONSOLE
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
<?php
|
|
||||||
$pronterfaceIP = "192.168.0.102:8080"; //Format: ip:port
|
|
||||||
|
|
||||||
$curl = curl_init();
|
|
||||||
curl_setopt($curl, CURLINFO_HEADER_OUT, true);
|
|
||||||
curl_setopt($curl, CURLOPT_HEADER, false);
|
|
||||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
|
||||||
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 1);
|
|
||||||
curl_setopt($curl,CURLOPT_TIMEOUT, 1);
|
|
||||||
curl_setopt($curl, CURLOPT_URL, "http://" . $pronterfaceIP . "/status/");
|
|
||||||
$data = curl_exec($curl);
|
|
||||||
|
|
||||||
if (curl_errno($curl) || empty($data))
|
|
||||||
{
|
|
||||||
die("Printer offline");
|
|
||||||
}
|
|
||||||
|
|
||||||
curl_close($curl);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
$xml = new SimpleXMLElement($data);
|
|
||||||
echo "State: " . $xml->state . "<br />";
|
|
||||||
echo "Hotend: " . round($xml->hotend, 0) . "°c<br />";
|
|
||||||
echo "Bed: " . round($xml->bed, 0) . "°c<br />";
|
|
||||||
if ($xml->progress != "NA")
|
|
||||||
{
|
|
||||||
echo "Progress: " . $xml->progress . "%";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(Exception $e)
|
|
||||||
{
|
|
||||||
echo "ERROR:\n" . $e->getMessage(). " (severity " . $e->getCode() . ")";
|
|
||||||
}
|
|
||||||
?>
|
|
|
@ -1,397 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# This file is part of the Printrun suite.
|
|
||||||
#
|
|
||||||
# Printrun is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Printrun is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with Printrun. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import pronterface
|
|
||||||
import cherrypy, re, ConfigParser, threading, sys
|
|
||||||
import os.path
|
|
||||||
|
|
||||||
from printrun.printrun_utils import configfile, imagefile, sharedfile
|
|
||||||
|
|
||||||
users = {}
|
|
||||||
|
|
||||||
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<script src="/js/asyncCommand.js"></script>\n</head>\n<body>\n'
|
|
||||||
|
|
||||||
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>'
|
|
||||||
|
|
||||||
def PrintFooter():
|
|
||||||
return "</body></html>"
|
|
||||||
|
|
||||||
def ReloadPage(action):
|
|
||||||
return "<html><head><meta http-equiv='refresh' content='0;url=/'></head><body>"+action+"</body></html>"
|
|
||||||
|
|
||||||
def TReloadPage(action):
|
|
||||||
return action
|
|
||||||
|
|
||||||
def clear_text(mypass):
|
|
||||||
return mypass
|
|
||||||
|
|
||||||
gPronterPtr = 0
|
|
||||||
gWeblog = ""
|
|
||||||
gLogRefresh =5
|
|
||||||
class SettingsPage(object):
|
|
||||||
def __init__(self):
|
|
||||||
self.name = "<div id='title'>Pronterface Settings</div>"
|
|
||||||
|
|
||||||
def index(self):
|
|
||||||
pageText = PrintHeader()+self.name+PrintMenu()
|
|
||||||
pageText = pageText+"<div id='settings'><table>\n<tr><th>setting</th><th>value</th>"
|
|
||||||
pageText = pageText+"<tr>\n <td><b>Build Dimenstions</b></td><td>"+str(gPronterPtr.settings.build_dimensions)+"</td>\n</tr>"
|
|
||||||
pageText = pageText+" <tr>\n <td><b>Last Bed Temp</b></td><td>"+str(gPronterPtr.settings.last_bed_temperature)+"</td>\n</tr>"
|
|
||||||
pageText = pageText+" <tr>\n <td><b>Last File Path</b></td><td>"+gPronterPtr.settings.last_file_path+"</td>\n</tr>"
|
|
||||||
pageText = pageText+" <tr>\n <td><b>Last Temperature</b></td><td>"+str(gPronterPtr.settings.last_temperature)+"</td>\n</tr>"
|
|
||||||
pageText = pageText+" <tr>\n <td><b>Preview Extrusion Width</b></td><td>"+str(gPronterPtr.settings.preview_extrusion_width)+"</td>\n</tr>"
|
|
||||||
pageText = pageText+" <tr>\n <td><b>Filename</b></td><td>"+str(gPronterPtr.filename)+"</td></tr></div>"
|
|
||||||
pageText = pageText+PrintFooter()
|
|
||||||
return pageText
|
|
||||||
index.exposed = True
|
|
||||||
|
|
||||||
class LogPage(object):
|
|
||||||
def __init__(self):
|
|
||||||
self.name = "<div id='title'>Pronterface Console</div>"
|
|
||||||
|
|
||||||
def index(self):
|
|
||||||
pageText = "<html><head><meta http-equiv='refresh' content='"+str(gLogRefresh)+"'></head><body>"
|
|
||||||
pageText+="<div id='status'>"
|
|
||||||
pageText+=gPronterPtr.status.GetStatusText()
|
|
||||||
pageText+="</div>"
|
|
||||||
pageText = pageText+"<div id='console'>"+gWeblog+"</div>"
|
|
||||||
pageText = pageText+"</body></html>"
|
|
||||||
return pageText
|
|
||||||
index.exposed = True
|
|
||||||
|
|
||||||
class ConsolePage(object):
|
|
||||||
def __init__(self):
|
|
||||||
self.name = "<div id='title'>Pronterface Settings</div>"
|
|
||||||
|
|
||||||
def index(self):
|
|
||||||
pageText = PrintHeader()+self.name+PrintMenu()
|
|
||||||
pageText+="<div id='logframe'><iframe src='/logpage' width='100%' height='100%'>iFraming Not Supported?? No log for you.</iframe></div>"
|
|
||||||
pageText+=PrintFooter()
|
|
||||||
return pageText
|
|
||||||
index.exposed = True
|
|
||||||
|
|
||||||
class ConnectButton(object):
|
|
||||||
def index(self):
|
|
||||||
#handle connect push, then reload page
|
|
||||||
gPronterPtr.connect(0)
|
|
||||||
return ReloadPage("Connect...")
|
|
||||||
index.exposed = True
|
|
||||||
index._cp_config = {'tools.basic_auth.on': True,
|
|
||||||
'tools.basic_auth.realm': 'My Print Server',
|
|
||||||
'tools.basic_auth.users': users,
|
|
||||||
'tools.basic_auth.encrypt': clear_text}
|
|
||||||
|
|
||||||
class DisconnectButton(object):
|
|
||||||
def index(self):
|
|
||||||
#handle connect push, then reload page
|
|
||||||
gPronterPtr.disconnect(0)
|
|
||||||
return ReloadPage("Disconnect...")
|
|
||||||
index.exposed = True
|
|
||||||
index._cp_config = {'tools.basic_auth.on': True,
|
|
||||||
'tools.basic_auth.realm': 'My Print Server',
|
|
||||||
'tools.basic_auth.users': users,
|
|
||||||
'tools.basic_auth.encrypt': clear_text}
|
|
||||||
|
|
||||||
class ResetButton(object):
|
|
||||||
def index(self):
|
|
||||||
#handle connect push, then reload page
|
|
||||||
gPronterPtr.reset(0)
|
|
||||||
return ReloadPage("Reset...")
|
|
||||||
index.exposed = True
|
|
||||||
index._cp_config = {'tools.basic_auth.on': True,
|
|
||||||
'tools.basic_auth.realm': 'My Print Server',
|
|
||||||
'tools.basic_auth.users': users,
|
|
||||||
'tools.basic_auth.encrypt': clear_text}
|
|
||||||
|
|
||||||
class PrintButton(object):
|
|
||||||
def index(self):
|
|
||||||
#handle connect push, then reload page
|
|
||||||
gPronterPtr.printfile(0)
|
|
||||||
return ReloadPage("Print...")
|
|
||||||
index.exposed = True
|
|
||||||
index._cp_config = {'tools.basic_auth.on': True,
|
|
||||||
'tools.basic_auth.realm': 'My Print Server',
|
|
||||||
'tools.basic_auth.users': users,
|
|
||||||
'tools.basic_auth.encrypt': clear_text}
|
|
||||||
|
|
||||||
class PauseButton(object):
|
|
||||||
def index(self):
|
|
||||||
#handle connect push, then reload page
|
|
||||||
gPronterPtr.pause(0)
|
|
||||||
return ReloadPage("Pause...")
|
|
||||||
index.exposed = True
|
|
||||||
index._cp_config = {'tools.basic_auth.on': True,
|
|
||||||
'tools.basic_auth.realm': 'My Print Server',
|
|
||||||
'tools.basic_auth.users': users,
|
|
||||||
'tools.basic_auth.encrypt': clear_text}
|
|
||||||
|
|
||||||
class MoveButton(object):
|
|
||||||
def axis(self, *args):
|
|
||||||
if not args:
|
|
||||||
raise cherrypy.HTTPError(400, "No Move Command Provided!")
|
|
||||||
margs = list(args)
|
|
||||||
axis = margs.pop(0)
|
|
||||||
if(margs and axis == "x"):
|
|
||||||
distance = margs.pop(0)
|
|
||||||
gPronterPtr.onecmd('move X %s' % distance)
|
|
||||||
return ReloadPage("Moving X Axis " + str(distance))
|
|
||||||
if(margs and axis == "y"):
|
|
||||||
distance = margs.pop(0)
|
|
||||||
gPronterPtr.onecmd('move Y %s' % distance)
|
|
||||||
return ReloadPage("Moving Y Axis " + str(distance))
|
|
||||||
if(margs and axis == "z"):
|
|
||||||
distance = margs.pop(0)
|
|
||||||
gPronterPtr.onecmd('move Z %s' % distance)
|
|
||||||
return ReloadPage("Moving Z Axis " + str(distance))
|
|
||||||
raise cherrypy.HTTPError(400, "Unmached Move Command!")
|
|
||||||
axis.exposed = True
|
|
||||||
axis._cp_config = {'tools.basic_auth.on': True,
|
|
||||||
'tools.basic_auth.realm': 'My Print Server',
|
|
||||||
'tools.basic_auth.users': users,
|
|
||||||
'tools.basic_auth.encrypt': clear_text}
|
|
||||||
|
|
||||||
class CustomButton(object):
|
|
||||||
def button(self, *args):
|
|
||||||
if not args:
|
|
||||||
raise cherrypy.HTTPError(400, "No Custom Command Provided!")
|
|
||||||
margs = list(args)
|
|
||||||
command = margs.pop(0)
|
|
||||||
if(command):
|
|
||||||
gPronterPtr.onecmd(command)
|
|
||||||
return ReloadPage(str(command))
|
|
||||||
button.exposed = True
|
|
||||||
button._cp_config = {'tools.basic_auth.on': True,
|
|
||||||
'tools.basic_auth.realm': 'My Print Server',
|
|
||||||
'tools.basic_auth.users': users,
|
|
||||||
'tools.basic_auth.encrypt': clear_text}
|
|
||||||
|
|
||||||
class HomeButton(object):
|
|
||||||
def axis(self, *args):
|
|
||||||
if not args:
|
|
||||||
raise cherrypy.HTTPError(400, "No Axis Provided!")
|
|
||||||
margs = list(args)
|
|
||||||
taxis = margs.pop(0)
|
|
||||||
if(taxis == "x"):
|
|
||||||
gPronterPtr.onecmd('home X')
|
|
||||||
return ReloadPage("Home X")
|
|
||||||
if(taxis == "y"):
|
|
||||||
gPronterPtr.onecmd('home Y')
|
|
||||||
return ReloadPage("Home Y")
|
|
||||||
if(taxis == "z"):
|
|
||||||
gPronterPtr.onecmd('home Z')
|
|
||||||
return ReloadPage("Home Z")
|
|
||||||
if(taxis == "all"):
|
|
||||||
gPronterPtr.onecmd('home')
|
|
||||||
return ReloadPage("Home All")
|
|
||||||
|
|
||||||
axis.exposed = True
|
|
||||||
axis._cp_config = {'tools.basic_auth.on': True,
|
|
||||||
'tools.basic_auth.realm': 'My Print Server',
|
|
||||||
'tools.basic_auth.users': users,
|
|
||||||
'tools.basic_auth.encrypt': clear_text}
|
|
||||||
|
|
||||||
class XMLstatus(object):
|
|
||||||
def index(self):
|
|
||||||
#handle connect push, then reload page
|
|
||||||
txt='<?xml version = "1.0"?>\n<pronterface>\n'
|
|
||||||
state = "Offline"
|
|
||||||
if gPronterPtr.statuscheck or gPronterPtr.p.online:
|
|
||||||
state = "Idle"
|
|
||||||
if gPronterPtr.sdprinting:
|
|
||||||
state = "SDPrinting"
|
|
||||||
if gPronterPtr.p.printing:
|
|
||||||
state = "Printing"
|
|
||||||
if gPronterPtr.paused:
|
|
||||||
state = "Paused"
|
|
||||||
|
|
||||||
txt = txt+'<state>'+state+'</state>\n'
|
|
||||||
txt = txt+'<file>'+str(gPronterPtr.filename)+'</file>\n'
|
|
||||||
txt = txt+'<status>'+str(gPronterPtr.status.GetStatusText())+'</status>\n'
|
|
||||||
try:
|
|
||||||
temp = str(float(filter(lambda x:x.startswith("T:"), gPronterPtr.tempreport.split())[0].split(":")[1]))
|
|
||||||
txt = txt+'<hotend>'+temp+'</hotend>\n'
|
|
||||||
except:
|
|
||||||
txt = txt+'<hotend>NA</hotend>\n'
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
temp = str(float(filter(lambda x:x.startswith("B:"), gPronterPtr.tempreport.split())[0].split(":")[1]))
|
|
||||||
txt = txt+'<bed>'+temp+'</bed>\n'
|
|
||||||
except:
|
|
||||||
txt = txt+'<bed>NA</bed>\n'
|
|
||||||
pass
|
|
||||||
if gPronterPtr.sdprinting:
|
|
||||||
fractioncomplete = float(gPronterPtr.percentdone/100.0)
|
|
||||||
txt+= _("<progress>%04.2f") % (gPronterPtr.percentdone,)
|
|
||||||
txt+="</progress>\n"
|
|
||||||
elif gPronterPtr.p.printing:
|
|
||||||
fractioncomplete = float(gPronterPtr.p.queueindex)/len(gPronterPtr.p.mainqueue)
|
|
||||||
txt+= _("<progress>%04.2f") % (100*float(gPronterPtr.p.queueindex)/len(gPronterPtr.p.mainqueue),)
|
|
||||||
txt+="</progress>\n"
|
|
||||||
else:
|
|
||||||
txt+="<progress>NA</progress>\n"
|
|
||||||
txt+='</pronterface>'
|
|
||||||
return txt
|
|
||||||
index.exposed = True
|
|
||||||
|
|
||||||
class WebInterface(object):
|
|
||||||
|
|
||||||
def __init__(self, pface):
|
|
||||||
if (sys.version_info[1] > 6):
|
|
||||||
# 'allow_no_value' wasn't added until 2.7
|
|
||||||
config = ConfigParser.SafeConfigParser(allow_no_value = True)
|
|
||||||
else:
|
|
||||||
config = ConfigParser.SafeConfigParser()
|
|
||||||
config.read(configfile(pface.web_auth_config or 'auth.config'))
|
|
||||||
users[config.get("user", "user")] = config.get("user", "pass")
|
|
||||||
self.pface = pface
|
|
||||||
global gPronterPtr
|
|
||||||
global gWeblog
|
|
||||||
self.name = "<div id='title'>Pronterface Web-Interface</div>"
|
|
||||||
gWeblog = ""
|
|
||||||
gPronterPtr = self.pface
|
|
||||||
|
|
||||||
settings = SettingsPage()
|
|
||||||
logpage = LogPage()
|
|
||||||
console = ConsolePage()
|
|
||||||
|
|
||||||
#actions
|
|
||||||
connect = ConnectButton()
|
|
||||||
disconnect = DisconnectButton()
|
|
||||||
reset = ResetButton()
|
|
||||||
printbutton = PrintButton()
|
|
||||||
pausebutton = PrintButton()
|
|
||||||
status = XMLstatus()
|
|
||||||
home = HomeButton()
|
|
||||||
move = MoveButton()
|
|
||||||
custom =CustomButton()
|
|
||||||
|
|
||||||
def index(self):
|
|
||||||
pageText = PrintHeader()+self.name+PrintMenu()
|
|
||||||
pageText+="<div id='content'>\n"
|
|
||||||
pageText+="<div id='controls'>\n"
|
|
||||||
pageText+="<ul><li><a class='command' href='/connect'>Connect</a></li>\n"
|
|
||||||
pageText+="<li><a class='command' href='/disconnect'>Disconnect</a></li>\n"
|
|
||||||
pageText+="<li><a class='command' href='/reset'>Reset</a></li>\n"
|
|
||||||
pageText+="<li><a class='command' href='/printbutton'>Print</a></li>\n"
|
|
||||||
pageText+="<li><a class='command' href='/pausebutton'>Pause</a></li>\n"
|
|
||||||
|
|
||||||
for i in gPronterPtr.cpbuttons:
|
|
||||||
pageText+="<li><a class='command' href='/custom/button/"+i.command+"'>"+i.label+"</a></li>\n"
|
|
||||||
|
|
||||||
#for i in gPronterPtr.custombuttons:
|
|
||||||
# print(str(i));
|
|
||||||
|
|
||||||
pageText+="</ul>\n"
|
|
||||||
pageText+="</div>\n"
|
|
||||||
pageText+="<div id='gui'>\n"
|
|
||||||
pageText+="<div id='control_xy'>"
|
|
||||||
pageText+="<img src='/images/control_xy.png' usemap='#xymap'/>"
|
|
||||||
pageText+='<map name = "xymap">'
|
|
||||||
|
|
||||||
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" class="command" coords = "195, 6, 236, 46" href = "/home/axis/y" alt = "Y Home" title = "Y 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" class="command" coords = "194, 192, 235, 232" href = "/home/axis/z" alt = "Z Home" title = "Z Home" />'
|
|
||||||
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" class="command" coords = "68, 34, 175, 61" href = "/move/axis/y/10" alt = "Y 10" title = "Y 10" />'
|
|
||||||
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" class="command" coords = "106, 83, 138, 107" 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" class="command" coords = "81, 157, 169, 181" href = "/move/axis/y/-1" alt = "Y -1" title = "Y -1" />'
|
|
||||||
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" class="command" coords = "60, 205, 186, 231" href = "/move/axis/y/-100" alt = "Y -100" title = "Y -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" class="command" coords = "210, 59, 236, 185" href = "/move/axis/x/100" alt = "X 100" title = "X 100" />'
|
|
||||||
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" class="command" coords = "185, 66, 211, 178" href = "/move/axis/x/10" alt = "X 10" title = "X 10" />'
|
|
||||||
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" class="command" coords = "163, 87, 187, 160" 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" class="command" coords = "137, 105, 165, 140" href = "/move/axis/x/.1" alt = "X .1" title = "X .1" />'
|
|
||||||
|
|
||||||
pageText+="</map>"
|
|
||||||
pageText+="</div>\n" #endxy
|
|
||||||
pageText+="<div id='control_z'>"
|
|
||||||
pageText+="<img src='/images/control_z.png' usemap='#zmap'/>"
|
|
||||||
pageText+='<map name = "zmap">'
|
|
||||||
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" class="command" coords = "4, 60, 54, 89" 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" class="command" coords = "4, 121, 54, 150" 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" class="command" coords = "4, 173, 54, 202" href = "/move/axis/z/-10" alt = "Z -10" title = "Z -10" />'
|
|
||||||
pageText+="</map>"
|
|
||||||
#TODO Map Z Moves
|
|
||||||
pageText+="</div>\n" #endz
|
|
||||||
pageText+="</div>\n" #endgui
|
|
||||||
pageText+="</div>\n" #endcontent
|
|
||||||
pageText+="</br>\n"
|
|
||||||
|
|
||||||
# Temp Control TBD
|
|
||||||
# pageText+="<div id='temp'>"
|
|
||||||
# pageText+="<div id='tempmenu'>"
|
|
||||||
# pageText+="<ul><li><b>Heater Temp:</b></li><li><a href='/off'>OFF</a></li><li><a href='/185'>185 (PLA)</a></li><li><a href='/240'>240 (ABS)</a></li></ul>"
|
|
||||||
# pageText+="</div>"
|
|
||||||
# pageText+="<div id='tempmenu'>"
|
|
||||||
# pageText+="<ul><li><b>Bed Temp:</b></li><li><a href='/off'>OFF</a></li><li><a href='/185'>185 (PLA)</a></li><li><a href='/240'>240 (ABS)</a></li></ul>"
|
|
||||||
# pageText+="</div>"
|
|
||||||
# pageText+="</div>"
|
|
||||||
|
|
||||||
pageText = pageText+"<div id='file'>File Loaded: <i>"+str(gPronterPtr.filename)+"</i></div>"
|
|
||||||
pageText+="<div id='logframe'><iframe src='/logpage' width='100%' height='100%'>iFraming Not Supported?? No log for you.</iframe></div>"
|
|
||||||
pageText+=PrintFooter()
|
|
||||||
return pageText
|
|
||||||
|
|
||||||
def AddLog(self, log):
|
|
||||||
global gWeblog
|
|
||||||
gWeblog = gWeblog+"</br>"+log
|
|
||||||
def AppendLog(self, log):
|
|
||||||
global gWeblog
|
|
||||||
gWeblog = re.sub("\n", "</br>", gWeblog)+log
|
|
||||||
index.exposed = True
|
|
||||||
|
|
||||||
class WebInterfaceStub(object):
|
|
||||||
def index(self):
|
|
||||||
return "<b>Web Interface Must be launched by running Pronterface!</b>"
|
|
||||||
index.exposed = True
|
|
||||||
|
|
||||||
def KillWebInterfaceThread():
|
|
||||||
cherrypy.engine.exit()
|
|
||||||
|
|
||||||
def StartWebInterfaceThread(webInterface):
|
|
||||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
cherrypy.config.update({'engine.autoreload_on':False})
|
|
||||||
cherrypy.config.update(configfile(webInterface.pface.web_config or "http.config"))
|
|
||||||
conf = {'/css/style.css': {'tools.staticfile.on': True,
|
|
||||||
'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,
|
|
||||||
'tools.staticfile.filename': imagefile('control_xy.png'),
|
|
||||||
},
|
|
||||||
'/images/control_z.png': {'tools.staticfile.on': True,
|
|
||||||
'tools.staticfile.filename': imagefile('control_z.png'),
|
|
||||||
}}
|
|
||||||
cherrypy.config.update(configfile(webInterface.pface.web_config or "http.config"))
|
|
||||||
cherrypy.quickstart(webInterface, '/', config = conf)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
cherrypy.config.update(configfile("http.config"))
|
|
||||||
cherrypy.quickstart(WebInterfaceStub())
|
|
|
@ -0,0 +1,403 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import tornado.ioloop
|
||||||
|
import tornado.web
|
||||||
|
import tornado.websocket
|
||||||
|
from tornado import gen
|
||||||
|
import tornado.httpserver
|
||||||
|
import time
|
||||||
|
import base64
|
||||||
|
import logging
|
||||||
|
import logging.config
|
||||||
|
import cmd, sys
|
||||||
|
import glob, os, time, datetime
|
||||||
|
import sys, subprocess
|
||||||
|
import math, codecs
|
||||||
|
from math import sqrt
|
||||||
|
from gcoder import GCode
|
||||||
|
import printcore
|
||||||
|
from pprint import pprint
|
||||||
|
import pronsole
|
||||||
|
from server import basic_auth
|
||||||
|
import random
|
||||||
|
import textwrap
|
||||||
|
import SocketServer
|
||||||
|
import socket
|
||||||
|
import mdns
|
||||||
|
import uuid
|
||||||
|
from operator import itemgetter, attrgetter
|
||||||
|
from collections import deque
|
||||||
|
|
||||||
|
log = logging.getLogger("root")
|
||||||
|
__UPLOADS__ = "./uploads"
|
||||||
|
|
||||||
|
# Authentication
|
||||||
|
# -------------------------------------------------
|
||||||
|
|
||||||
|
def authenticator(realm,handle,password):
|
||||||
|
"""
|
||||||
|
This method is a sample authenticator.
|
||||||
|
It treats authentication as successful
|
||||||
|
if the handle and passwords are the same.
|
||||||
|
It returns a tuple of handle and user name
|
||||||
|
"""
|
||||||
|
if handle == "admin" and password == "admin" :
|
||||||
|
return (handle,'Authorized User')
|
||||||
|
return None
|
||||||
|
|
||||||
|
def user_extractor(user_data):
|
||||||
|
"""
|
||||||
|
This method extracts the user handle from
|
||||||
|
the data structure returned by the authenticator
|
||||||
|
"""
|
||||||
|
return user_data[0]
|
||||||
|
|
||||||
|
def socket_auth(self):
|
||||||
|
user = self.get_argument("user", None)
|
||||||
|
password = self.get_argument("password", None)
|
||||||
|
return authenticator(None, user, password)
|
||||||
|
|
||||||
|
interceptor = basic_auth.interceptor
|
||||||
|
auth = basic_auth.authenticate('auth_realm', authenticator, user_extractor)
|
||||||
|
#@interceptor(auth)
|
||||||
|
|
||||||
|
|
||||||
|
# Routing
|
||||||
|
# -------------------------------------------------
|
||||||
|
|
||||||
|
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]
|
||||||
|
pronserve.jobs.add(fileinfo['filename'], fileinfo['body'])
|
||||||
|
self.finish("ACK")
|
||||||
|
|
||||||
|
class JobHandler(tornado.web.RequestHandler):
|
||||||
|
def delete(self, job_id):
|
||||||
|
pronserve.jobs.remove(int(job_id))
|
||||||
|
self.finish("ACK")
|
||||||
|
|
||||||
|
def put(self, job_id):
|
||||||
|
args = {'position': int(self.get_argument("job[position]"))}
|
||||||
|
pronserve.jobs.update(int(job_id), args)
|
||||||
|
self.finish("ACK")
|
||||||
|
|
||||||
|
|
||||||
|
class InspectHandler(tornado.web.RequestHandler):
|
||||||
|
def prepare(self):
|
||||||
|
auth(self, None)
|
||||||
|
|
||||||
|
def get(self):
|
||||||
|
self.render("inspect.html")
|
||||||
|
|
||||||
|
#class EchoWebSocketHandler(tornado.web.RequestHandler):
|
||||||
|
class ConstructSocketHandler(tornado.websocket.WebSocketHandler):
|
||||||
|
|
||||||
|
def on_sensor_changed(self):
|
||||||
|
for name in ['bed', 'extruder']:
|
||||||
|
self.send(
|
||||||
|
sensor_changed= {'name': name, 'value': pronserve.sensors[name]},
|
||||||
|
)
|
||||||
|
|
||||||
|
def on_uncaught_event(self, event_name, data):
|
||||||
|
listener = "on_%s"%event_name
|
||||||
|
|
||||||
|
if event_name[:4] == 'job_' and event_name != "job_progress_changed":
|
||||||
|
data = pronserve.jobs.sanitize(data)
|
||||||
|
self.send({event_name: data})
|
||||||
|
|
||||||
|
def _execute(self, transforms, *args, **kwargs):
|
||||||
|
if socket_auth(self):
|
||||||
|
super(ConstructSocketHandler, self)._execute(transforms, *args, **kwargs)
|
||||||
|
else:
|
||||||
|
self.stream.close();
|
||||||
|
|
||||||
|
def open(self):
|
||||||
|
pronserve.listeners.add(self)
|
||||||
|
self.write_message({'connected': {'jobs': pronserve.jobs.public_list()}})
|
||||||
|
print "WebSocket opened. %i sockets currently open." % len(pronserve.listeners)
|
||||||
|
|
||||||
|
def send(self, dict_args = {}, **kwargs):
|
||||||
|
args = dict(dict_args.items() + kwargs.items())
|
||||||
|
args['timestamp']= time.time()
|
||||||
|
self.write_message(args)
|
||||||
|
|
||||||
|
def on_message(self, msg):
|
||||||
|
print "message received: %s"%(msg)
|
||||||
|
# TODO: the read bit of repl!
|
||||||
|
# self.write_message("You said: " + msg)
|
||||||
|
|
||||||
|
def on_close(self):
|
||||||
|
pronserve.listeners.remove(self)
|
||||||
|
print "WebSocket closed. %i sockets currently open." % len(pronserve.listeners)
|
||||||
|
|
||||||
|
dir = os.path.dirname(__file__)
|
||||||
|
settings = dict(
|
||||||
|
template_path=os.path.join(dir, "server", "templates"),
|
||||||
|
static_path=os.path.join(dir, "server", "static"),
|
||||||
|
debug=True
|
||||||
|
)
|
||||||
|
|
||||||
|
application = tornado.web.Application([
|
||||||
|
(r"/", RootHandler),
|
||||||
|
(r"/inspect", InspectHandler),
|
||||||
|
(r"/socket", ConstructSocketHandler),
|
||||||
|
(r"/jobs", JobsHandler),
|
||||||
|
(r"/jobs/([0-9]*)", JobHandler),
|
||||||
|
(r"/jobs/print", PrintHandler),
|
||||||
|
(r"/jobs/pause", PauseHandler),
|
||||||
|
(r"/stop", StopHandler)
|
||||||
|
], **settings)
|
||||||
|
|
||||||
|
|
||||||
|
# Event Emitter
|
||||||
|
# -------------------------------------------------
|
||||||
|
|
||||||
|
class EventEmitter(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.listeners = set()
|
||||||
|
|
||||||
|
def fire(self, event_name, content=None):
|
||||||
|
callback_name = "on_%s" % event_name
|
||||||
|
for listener in self.listeners:
|
||||||
|
if hasattr(listener, callback_name):
|
||||||
|
callback = getattr(listener, callback_name)
|
||||||
|
if content == None: callback()
|
||||||
|
else: callback(content)
|
||||||
|
elif hasattr(listener, "on_uncaught_event"):
|
||||||
|
listener.on_uncaught_event(event_name, content)
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
|
|
||||||
|
# Pronserve: Server-specific functionality
|
||||||
|
# -------------------------------------------------
|
||||||
|
|
||||||
|
class Pronserve(pronsole.pronsole, EventEmitter):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
pronsole.pronsole.__init__(self)
|
||||||
|
EventEmitter.__init__(self)
|
||||||
|
self.settings.sensor_names = {'T': 'extruder', 'B': 'bed'}
|
||||||
|
self.stdout = sys.stdout
|
||||||
|
self.ioloop = tornado.ioloop.IOLoop.instance()
|
||||||
|
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.printing_jobs = False
|
||||||
|
self.current_job = None
|
||||||
|
self.previous_job_progress = 0
|
||||||
|
self.silent = True
|
||||||
|
services = ({'type': '_construct._tcp', 'port': 8888, 'domain': "local."})
|
||||||
|
self.mdns = mdns.publisher().save_group({'name': 'pronserve', 'services': services })
|
||||||
|
self.jobs.listeners.add(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
|
||||||
|
gen.Task(self.ioloop.add_timeout(next_timeout, self.run_sensor_loop))
|
||||||
|
|
||||||
|
def request_sensor_update(self):
|
||||||
|
if self.p.online: self.p.send_now("M105")
|
||||||
|
|
||||||
|
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 = 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_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)
|
||||||
|
|
||||||
|
def on_uncaught_event(self, event_name, content=None):
|
||||||
|
self.fire(event_name, content)
|
||||||
|
|
||||||
|
def log(self, *msg):
|
||||||
|
msg = ''.join(str(i) for i in msg)
|
||||||
|
msg.replace("\r", "")
|
||||||
|
print msg
|
||||||
|
self.fire("log", {'msg': msg, 'level': "debug"})
|
||||||
|
|
||||||
|
def write_prompt(self):
|
||||||
|
None
|
||||||
|
|
||||||
|
|
||||||
|
class PrintJobQueue(EventEmitter):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(PrintJobQueue, self).__init__()
|
||||||
|
self.list = deque([])
|
||||||
|
self.__last_id = 0
|
||||||
|
|
||||||
|
def public_list(self):
|
||||||
|
# A sanitized version of list for public consumption via construct
|
||||||
|
l2 = []
|
||||||
|
for job in self.list:
|
||||||
|
l2.append(self.sanitize(job))
|
||||||
|
return l2
|
||||||
|
|
||||||
|
def sanitize(self, job):
|
||||||
|
return dict(
|
||||||
|
id = job["id"],
|
||||||
|
original_file_name = job["original_file_name"],
|
||||||
|
rank = job["rank"]
|
||||||
|
)
|
||||||
|
|
||||||
|
def order(self):
|
||||||
|
sorted(self.list, key=lambda job: job['rank'])
|
||||||
|
|
||||||
|
|
||||||
|
def add(self, original_file_name, body):
|
||||||
|
ext = os.path.splitext(original_file_name)[1]
|
||||||
|
job = dict(
|
||||||
|
id = self.__last_id,
|
||||||
|
rank = len(self.list),
|
||||||
|
original_file_name=original_file_name,
|
||||||
|
body= body,
|
||||||
|
)
|
||||||
|
self.__last_id += 1
|
||||||
|
|
||||||
|
self.list.append(job)
|
||||||
|
print "Added %s"%(original_file_name)
|
||||||
|
self.fire("job_added", job)
|
||||||
|
|
||||||
|
def display_summary(self):
|
||||||
|
print "Print Jobs:"
|
||||||
|
for job in self.list:
|
||||||
|
print " %i: %s"%(job['id'], job['original_file_name'])
|
||||||
|
print ""
|
||||||
|
return True
|
||||||
|
|
||||||
|
def remove(self, job_id):
|
||||||
|
job = self.find_by_id(job_id)
|
||||||
|
if job == None:
|
||||||
|
return False
|
||||||
|
self.list.remove(job)
|
||||||
|
print "Print Job Removed"
|
||||||
|
self.fire("job_removed", job)
|
||||||
|
|
||||||
|
def update(self, job_id, job_attrs):
|
||||||
|
job = self.find_by_id(job_id)
|
||||||
|
if job == None:
|
||||||
|
return False
|
||||||
|
job['rank'] = job_attrs['position']
|
||||||
|
self.order()
|
||||||
|
print "Print Job Updated"
|
||||||
|
self.fire("job_updated", job)
|
||||||
|
|
||||||
|
def find_by_id(self, job_id):
|
||||||
|
for job in self.list:
|
||||||
|
if job['id'] == job_id: return job
|
||||||
|
return None
|
||||||
|
|
||||||
|
def fire(self, event_name, content):
|
||||||
|
self.display_summary()
|
||||||
|
super(PrintJobQueue, self).fire(event_name, content)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Server Start Up
|
||||||
|
# -------------------------------------------------
|
||||||
|
|
||||||
|
print "Pronserve is starting..."
|
||||||
|
pronserve = Pronserve()
|
||||||
|
pronserve.do_connect("")
|
||||||
|
|
||||||
|
time.sleep(1)
|
||||||
|
pronserve.run_sensor_loop()
|
||||||
|
pronserve.run_print_queue_loop()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
application.listen(8888)
|
||||||
|
print "\n"+"-"*80
|
||||||
|
welcome = textwrap.dedent(u"""
|
||||||
|
+---+ \x1B[0;32mPronserve: Your printer just got a whole lot better.\x1B[0m
|
||||||
|
| \u2713 | Ready to print.
|
||||||
|
+---+ More details at http://localhost:8888/""")
|
||||||
|
sys.stdout.write(welcome)
|
||||||
|
print "\n\n" + "-"*80 + "\n"
|
||||||
|
|
||||||
|
try:
|
||||||
|
pronserve.ioloop.start()
|
||||||
|
except:
|
||||||
|
pronserve.p.disconnect()
|
378
pronsole.py
378
pronsole.py
|
@ -77,7 +77,7 @@ def estimate_duration(g):
|
||||||
#TODO:
|
#TODO:
|
||||||
# get device caps from firmware: max speed, acceleration/axis (including extruder)
|
# get device caps from firmware: max speed, acceleration/axis (including extruder)
|
||||||
# calculate the maximum move duration accounting for above ;)
|
# calculate the maximum move duration accounting for above ;)
|
||||||
# print ".... estimating ...."
|
# self.log(".... estimating ....")
|
||||||
for i in g:
|
for i in g:
|
||||||
i = i.split(";")[0]
|
i = i.split(";")[0]
|
||||||
if "G4" in i or "G1" in i:
|
if "G4" in i or "G1" in i:
|
||||||
|
@ -119,7 +119,7 @@ def estimate_duration(g):
|
||||||
|
|
||||||
if z > lastz:
|
if z > lastz:
|
||||||
layercount +=1
|
layercount +=1
|
||||||
#print "layer z: ", lastz, " will take: ", time.strftime('%H:%M:%S', time.gmtime(totalduration-layerbeginduration))
|
#self.log("layer z: ", lastz, " will take: ", time.strftime('%H:%M:%S', time.gmtime(totalduration-layerbeginduration)))
|
||||||
layerbeginduration = totalduration
|
layerbeginduration = totalduration
|
||||||
|
|
||||||
lastx = x
|
lastx = x
|
||||||
|
@ -128,7 +128,7 @@ def estimate_duration(g):
|
||||||
laste = e
|
laste = e
|
||||||
lastf = f
|
lastf = f
|
||||||
|
|
||||||
#print "Total Duration: " #, time.strftime('%H:%M:%S', time.gmtime(totalduration))
|
#self.log("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():
|
def confirm():
|
||||||
|
@ -252,6 +252,7 @@ class pronsole(cmd.Cmd):
|
||||||
self.settings._bedtemp_abs_cb = self.set_temp_preset
|
self.settings._bedtemp_abs_cb = self.set_temp_preset
|
||||||
self.settings._bedtemp_pla_cb = self.set_temp_preset
|
self.settings._bedtemp_pla_cb = self.set_temp_preset
|
||||||
self.monitoring = 0
|
self.monitoring = 0
|
||||||
|
self.silent = False
|
||||||
self.helpdict = {}
|
self.helpdict = {}
|
||||||
self.helpdict["baudrate"] = _("Communications Speed (default: 115200)")
|
self.helpdict["baudrate"] = _("Communications Speed (default: 115200)")
|
||||||
self.helpdict["bedtemp_abs"] = _("Heated Build Platform temp for ABS (default: 110 deg C)")
|
self.helpdict["bedtemp_abs"] = _("Heated Build Platform temp for ABS (default: 110 deg C)")
|
||||||
|
@ -274,6 +275,9 @@ class pronsole(cmd.Cmd):
|
||||||
"macro" : "%(bold)s..>%(normal)s ",
|
"macro" : "%(bold)s..>%(normal)s ",
|
||||||
"online" : "%(bold)sT:%(extruder_temp_fancy)s %(progress_fancy)s >%(normal)s "}
|
"online" : "%(bold)sT:%(extruder_temp_fancy)s %(progress_fancy)s >%(normal)s "}
|
||||||
|
|
||||||
|
def log(self, *msg):
|
||||||
|
print ''.join(str(i) for i in msg)
|
||||||
|
|
||||||
def promptf(self):
|
def promptf(self):
|
||||||
"""A function to generate prompts so that we can do dynamic prompts. """
|
"""A function to generate prompts so that we can do dynamic prompts. """
|
||||||
if self.in_macro:
|
if self.in_macro:
|
||||||
|
@ -323,11 +327,11 @@ class pronsole(cmd.Cmd):
|
||||||
if not key.startswith("bed"):
|
if not key.startswith("bed"):
|
||||||
self.temps["pla"] = str(self.settings.temperature_pla)
|
self.temps["pla"] = str(self.settings.temperature_pla)
|
||||||
self.temps["abs"] = str(self.settings.temperature_abs)
|
self.temps["abs"] = str(self.settings.temperature_abs)
|
||||||
print "Hotend temperature presets updated, pla:%s, abs:%s" % (self.temps["pla"], self.temps["abs"])
|
self.log("Hotend temperature presets updated, pla:%s, abs:%s" % (self.temps["pla"], self.temps["abs"]))
|
||||||
else:
|
else:
|
||||||
self.bedtemps["pla"] = str(self.settings.bedtemp_pla)
|
self.bedtemps["pla"] = str(self.settings.bedtemp_pla)
|
||||||
self.bedtemps["abs"] = str(self.settings.bedtemp_abs)
|
self.bedtemps["abs"] = str(self.settings.bedtemp_abs)
|
||||||
print "Bed temperature presets updated, pla:%s, abs:%s" % (self.bedtemps["pla"], self.bedtemps["abs"])
|
self.log("Bed temperature presets updated, pla:%s, abs:%s" % (self.bedtemps["pla"], self.bedtemps["abs"]))
|
||||||
|
|
||||||
def scanserial(self):
|
def scanserial(self):
|
||||||
"""scan for available ports. return a list of device names."""
|
"""scan for available ports. return a list of device names."""
|
||||||
|
@ -345,7 +349,10 @@ 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 "\rPrinter is now online"
|
self.log("\rPrinter is now online")
|
||||||
|
self.write_prompt()
|
||||||
|
|
||||||
|
def write_prompt(self):
|
||||||
sys.stdout.write(self.promptf())
|
sys.stdout.write(self.promptf())
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
@ -356,7 +363,7 @@ class pronsole(cmd.Cmd):
|
||||||
self.help_gcodes()
|
self.help_gcodes()
|
||||||
|
|
||||||
def help_gcodes(self):
|
def help_gcodes(self):
|
||||||
print "Gcodes are passed through to the printer as they are"
|
self.log("Gcodes are passed through to the printer as they are")
|
||||||
|
|
||||||
def complete_macro(self, text, line, begidx, endidx):
|
def complete_macro(self, text, line, begidx, endidx):
|
||||||
if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1]==" "):
|
if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1]==" "):
|
||||||
|
@ -386,7 +393,7 @@ class pronsole(cmd.Cmd):
|
||||||
setattr(self.__class__, "do_"+self.cur_macro_name, lambda self, largs, macro = macro:macro(self,*largs.split()))
|
setattr(self.__class__, "do_"+self.cur_macro_name, lambda self, largs, macro = macro:macro(self,*largs.split()))
|
||||||
setattr(self.__class__, "help_"+self.cur_macro_name, lambda self, macro_name = self.cur_macro_name: self.subhelp_macro(macro_name))
|
setattr(self.__class__, "help_"+self.cur_macro_name, lambda self, macro_name = self.cur_macro_name: self.subhelp_macro(macro_name))
|
||||||
if not self.processing_rc:
|
if not self.processing_rc:
|
||||||
print "Macro '"+self.cur_macro_name+"' defined"
|
self.log("Macro '"+self.cur_macro_name+"' defined")
|
||||||
# save it
|
# save it
|
||||||
if not self.processing_args:
|
if not self.processing_args:
|
||||||
macro_key = "macro "+self.cur_macro_name
|
macro_key = "macro "+self.cur_macro_name
|
||||||
|
@ -398,7 +405,7 @@ class pronsole(cmd.Cmd):
|
||||||
macro_def += self.cur_macro_def
|
macro_def += self.cur_macro_def
|
||||||
self.save_in_rc(macro_key, macro_def)
|
self.save_in_rc(macro_key, macro_def)
|
||||||
else:
|
else:
|
||||||
print "Empty macro - cancelled"
|
self.log("Empty macro - cancelled")
|
||||||
del self.cur_macro_name, self.cur_macro_def
|
del self.cur_macro_name, self.cur_macro_def
|
||||||
|
|
||||||
def compile_macro_line(self, line):
|
def compile_macro_line(self, line):
|
||||||
|
@ -413,7 +420,7 @@ class pronsole(cmd.Cmd):
|
||||||
|
|
||||||
def compile_macro(self, macro_name, macro_def):
|
def compile_macro(self, macro_name, macro_def):
|
||||||
if macro_def.strip() == "":
|
if macro_def.strip() == "":
|
||||||
print "Empty macro - cancelled"
|
self.log("Empty macro - cancelled")
|
||||||
return
|
return
|
||||||
pycode = "def macro(self,*arg):\n"
|
pycode = "def macro(self,*arg):\n"
|
||||||
if "\n" not in macro_def.strip():
|
if "\n" not in macro_def.strip():
|
||||||
|
@ -427,7 +434,7 @@ class pronsole(cmd.Cmd):
|
||||||
|
|
||||||
def start_macro(self, macro_name, prev_definition = "", suppress_instructions = False):
|
def start_macro(self, macro_name, prev_definition = "", suppress_instructions = False):
|
||||||
if not self.processing_rc and not suppress_instructions:
|
if not self.processing_rc and not suppress_instructions:
|
||||||
print "Enter macro using indented lines, end with empty line"
|
self.log("Enter macro using indented lines, end with empty line")
|
||||||
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
|
||||||
|
@ -438,11 +445,11 @@ class pronsole(cmd.Cmd):
|
||||||
if macro_name in self.macros.keys():
|
if macro_name in self.macros.keys():
|
||||||
delattr(self.__class__, "do_"+macro_name)
|
delattr(self.__class__, "do_"+macro_name)
|
||||||
del self.macros[macro_name]
|
del self.macros[macro_name]
|
||||||
print "Macro '"+macro_name+"' removed"
|
self.log("Macro '"+macro_name+"' removed")
|
||||||
if not self.processing_rc and not self.processing_args:
|
if not self.processing_rc and not self.processing_args:
|
||||||
self.save_in_rc("macro "+macro_name, "")
|
self.save_in_rc("macro "+macro_name, "")
|
||||||
else:
|
else:
|
||||||
print "Macro '"+macro_name+"' is not defined"
|
self.log("Macro '"+macro_name+"' is not defined")
|
||||||
def do_macro(self, args):
|
def do_macro(self, args):
|
||||||
if args.strip()=="":
|
if args.strip()=="":
|
||||||
self.print_topics("User-defined macros", self.macros.keys(), 15, 80)
|
self.print_topics("User-defined macros", self.macros.keys(), 15, 80)
|
||||||
|
@ -450,7 +457,7 @@ class pronsole(cmd.Cmd):
|
||||||
arglist = args.split(None, 1)
|
arglist = args.split(None, 1)
|
||||||
macro_name = arglist[0]
|
macro_name = arglist[0]
|
||||||
if macro_name not in self.macros and hasattr(self.__class__, "do_"+macro_name):
|
if macro_name not in self.macros and hasattr(self.__class__, "do_"+macro_name):
|
||||||
print "Name '"+macro_name+"' is being used by built-in command"
|
self.log("Name '"+macro_name+"' is being used by built-in command")
|
||||||
return
|
return
|
||||||
if len(arglist) == 2:
|
if len(arglist) == 2:
|
||||||
macro_def = arglist[1]
|
macro_def = arglist[1]
|
||||||
|
@ -470,24 +477,24 @@ class pronsole(cmd.Cmd):
|
||||||
self.start_macro(macro_name)
|
self.start_macro(macro_name)
|
||||||
|
|
||||||
def help_macro(self):
|
def help_macro(self):
|
||||||
print "Define single-line macro: macro <name> <definition>"
|
self.log("Define single-line macro: macro <name> <definition>")
|
||||||
print "Define multi-line macro: macro <name>"
|
self.log("Define multi-line macro: macro <name>")
|
||||||
print "Enter macro definition in indented lines. Use {0} .. {N} to substitute macro arguments"
|
self.log("Enter macro definition in indented lines. Use {0} .. {N} to substitute macro arguments")
|
||||||
print "Enter python code, prefixed with ! Use arg[0] .. arg[N] to substitute macro arguments"
|
self.log("Enter python code, prefixed with ! Use arg[0] .. arg[N] to substitute macro arguments")
|
||||||
print "Delete macro: macro <name> /d"
|
self.log("Delete macro: macro <name> /d")
|
||||||
print "Show macro definition: macro <name> /s"
|
self.log("Show macro definition: macro <name> /s")
|
||||||
print "'macro' without arguments displays list of defined macros"
|
self.log("'macro' without arguments displays list of defined macros")
|
||||||
|
|
||||||
def subhelp_macro(self, macro_name):
|
def subhelp_macro(self, macro_name):
|
||||||
if macro_name in self.macros.keys():
|
if macro_name in self.macros.keys():
|
||||||
macro_def = self.macros[macro_name]
|
macro_def = self.macros[macro_name]
|
||||||
if "\n" in macro_def:
|
if "\n" in macro_def:
|
||||||
print "Macro '"+macro_name+"' defined as:"
|
self.log("Macro '"+macro_name+"' defined as:")
|
||||||
print self.macros[macro_name]+"----------------"
|
self.log(self.macros[macro_name]+"----------------")
|
||||||
else:
|
else:
|
||||||
print "Macro '"+macro_name+"' defined as: '"+macro_def+"'"
|
self.log("Macro '"+macro_name+"' defined as: '"+macro_def+"'")
|
||||||
else:
|
else:
|
||||||
print "Macro '"+macro_name+"' is not defined"
|
self.log("Macro '"+macro_name+"' is not defined")
|
||||||
|
|
||||||
def set(self, var, str):
|
def set(self, var, str):
|
||||||
try:
|
try:
|
||||||
|
@ -496,29 +503,29 @@ class pronsole(cmd.Cmd):
|
||||||
if not self.processing_rc and not self.processing_args:
|
if not self.processing_rc and not self.processing_args:
|
||||||
self.save_in_rc("set "+var, "set %s %s" % (var, value))
|
self.save_in_rc("set "+var, "set %s %s" % (var, value))
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
print "Unknown variable '%s'" % var
|
self.log("Unknown variable '%s'" % var)
|
||||||
except ValueError, ve:
|
except ValueError, ve:
|
||||||
print "Bad value for variable '%s', expecting %s (%s)" % (var, repr(t)[1:-1], ve.args[0])
|
self.log("Bad value for variable '%s', expecting %s (%s)" % (var, repr(t)[1:-1], ve.args[0]))
|
||||||
|
|
||||||
def do_set(self, argl):
|
def do_set(self, argl):
|
||||||
args = argl.split(None, 1)
|
args = argl.split(None, 1)
|
||||||
if len(args) < 1:
|
if len(args) < 1:
|
||||||
for k in [kk for kk in dir(self.settings) if not kk.startswith("_")]:
|
for k in [kk for kk in dir(self.settings) if not kk.startswith("_")]:
|
||||||
print "%s = %s" % (k, str(getattr(self.settings, k)))
|
self.log("%s = %s" % (k, str(getattr(self.settings, k))))
|
||||||
return
|
return
|
||||||
value = getattr(self.settings, args[0])
|
value = getattr(self.settings, args[0])
|
||||||
if len(args) < 2:
|
if len(args) < 2:
|
||||||
try:
|
try:
|
||||||
print "%s = %s" % (args[0], getattr(self.settings, args[0]))
|
self.log("%s = %s" % (args[0], getattr(self.settings, args[0])))
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
print "Unknown variable '%s'" % args[0]
|
self.log("Unknown variable '%s'" % args[0])
|
||||||
return
|
return
|
||||||
self.set(args[0], args[1])
|
self.set(args[0], args[1])
|
||||||
|
|
||||||
def help_set(self):
|
def help_set(self):
|
||||||
print "Set variable: set <variable> <value>"
|
self.log("Set variable: set <variable> <value>")
|
||||||
print "Show variable: set <variable>"
|
self.log("Show variable: set <variable>")
|
||||||
print "'set' without arguments displays all variables"
|
self.log("'set' without arguments displays all variables")
|
||||||
|
|
||||||
def complete_set(self, text, line, begidx, endidx):
|
def complete_set(self, text, line, begidx, endidx):
|
||||||
if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1]==" "):
|
if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1]==" "):
|
||||||
|
@ -600,16 +607,16 @@ class pronsole(cmd.Cmd):
|
||||||
rci.close()
|
rci.close()
|
||||||
rco.close()
|
rco.close()
|
||||||
#if definition != "":
|
#if definition != "":
|
||||||
# print "Saved '"+key+"' to '"+self.rc_filename+"'"
|
# self.log("Saved '"+key+"' to '"+self.rc_filename+"'")
|
||||||
#else:
|
#else:
|
||||||
# print "Removed '"+key+"' from '"+self.rc_filename+"'"
|
# self.log("Removed '"+key+"' from '"+self.rc_filename+"'")
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
print "Saving failed for", key+":", str(e)
|
self.log("Saving failed for", key+":", str(e))
|
||||||
finally:
|
finally:
|
||||||
del rci, rco
|
del rci, rco
|
||||||
|
|
||||||
def preloop(self):
|
def preloop(self):
|
||||||
print "Welcome to the printer console! Type \"help\" for a list of available commands."
|
self.log("Welcome to the printer console! Type \"help\" for a list of available commands.")
|
||||||
self.prompt = self.promptf()
|
self.prompt = self.promptf()
|
||||||
cmd.Cmd.preloop(self)
|
cmd.Cmd.preloop(self)
|
||||||
|
|
||||||
|
@ -626,12 +633,12 @@ class pronsole(cmd.Cmd):
|
||||||
try:
|
try:
|
||||||
baud = int(a[1])
|
baud = int(a[1])
|
||||||
except:
|
except:
|
||||||
print "Bad baud value '"+a[1]+"' ignored"
|
self.log("Bad baud value '"+a[1]+"' ignored")
|
||||||
if len(p) == 0 and not port:
|
if len(p) == 0 and not port:
|
||||||
print "No serial ports detected - please specify a port"
|
self.log("No serial ports detected - please specify a port")
|
||||||
return
|
return
|
||||||
if len(a) == 0:
|
if len(a) == 0:
|
||||||
print "No port specified - connecting to %s at %dbps" % (port, baud)
|
self.log("No port specified - connecting to %s at %dbps" % (port, baud))
|
||||||
if port != self.settings.port:
|
if port != self.settings.port:
|
||||||
self.settings.port = port
|
self.settings.port = port
|
||||||
self.save_in_rc("set port", "set port %s" % port)
|
self.save_in_rc("set port", "set port %s" % port)
|
||||||
|
@ -641,14 +648,14 @@ class pronsole(cmd.Cmd):
|
||||||
self.p.connect(port, baud)
|
self.p.connect(port, baud)
|
||||||
|
|
||||||
def help_connect(self):
|
def help_connect(self):
|
||||||
print "Connect to printer"
|
self.log("Connect to printer")
|
||||||
print "connect <port> <baudrate>"
|
self.log("connect <port> <baudrate>")
|
||||||
print "If port and baudrate are not specified, connects to first detected port at 115200bps"
|
self.log("If port and baudrate are not specified, connects to first detected port at 115200bps")
|
||||||
ports = self.scanserial()
|
ports = self.scanserial()
|
||||||
if(len(ports)):
|
if(len(ports)):
|
||||||
print "Available ports: ", " ".join(ports)
|
self.log("Available ports: ", " ".join(ports))
|
||||||
else:
|
else:
|
||||||
print "No serial ports were automatically found."
|
self.log("No serial ports were automatically found.")
|
||||||
|
|
||||||
def complete_connect(self, text, line, begidx, endidx):
|
def complete_connect(self, text, line, begidx, endidx):
|
||||||
if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1]==" "):
|
if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1]==" "):
|
||||||
|
@ -662,22 +669,22 @@ class pronsole(cmd.Cmd):
|
||||||
self.p.disconnect()
|
self.p.disconnect()
|
||||||
|
|
||||||
def help_disconnect(self):
|
def help_disconnect(self):
|
||||||
print "Disconnects from the printer"
|
self.log("Disconnects from the printer")
|
||||||
|
|
||||||
def do_load(self,l):
|
def do_load(self,l):
|
||||||
self._do_load(l)
|
self._do_load(l)
|
||||||
|
|
||||||
def _do_load(self,l):
|
def _do_load(self,l):
|
||||||
if len(l)==0:
|
if len(l)==0:
|
||||||
print "No file name given."
|
self.log("No file name given.")
|
||||||
return
|
return
|
||||||
print "Loading file:"+l
|
self.log("Loading file:"+l)
|
||||||
if not(os.path.exists(l)):
|
if not(os.path.exists(l)):
|
||||||
print "File not found!"
|
self.log("File not found!")
|
||||||
return
|
return
|
||||||
self.f = [i.replace("\n", "").replace("\r", "") for i in open(l)]
|
self.f = [i.replace("\n", "").replace("\r", "") for i in open(l)]
|
||||||
self.filename = l
|
self.filename = l
|
||||||
print "Loaded ", l, ", ", len(self.f)," lines."
|
self.log("Loaded ", l, ", ", len(self.f)," lines.")
|
||||||
|
|
||||||
def complete_load(self, text, line, begidx, endidx):
|
def complete_load(self, text, line, begidx, endidx):
|
||||||
s = line.split()
|
s = line.split()
|
||||||
|
@ -690,32 +697,32 @@ class pronsole(cmd.Cmd):
|
||||||
return glob.glob("*/")+glob.glob("*.g*")
|
return glob.glob("*/")+glob.glob("*.g*")
|
||||||
|
|
||||||
def help_load(self):
|
def help_load(self):
|
||||||
print "Loads a gcode file (with tab-completion)"
|
self.log("Loads a gcode file (with tab-completion)")
|
||||||
|
|
||||||
def do_upload(self, l):
|
def do_upload(self, l):
|
||||||
if len(l) == 0:
|
if len(l) == 0:
|
||||||
print "No file name given."
|
self.log("No file name given.")
|
||||||
return
|
return
|
||||||
print "Loading file:"+l.split()[0]
|
self.log("Loading file:"+l.split()[0])
|
||||||
if not(os.path.exists(l.split()[0])):
|
if not(os.path.exists(l.split()[0])):
|
||||||
print "File not found!"
|
self.log("File not found!")
|
||||||
return
|
return
|
||||||
if not self.p.online:
|
if not self.p.online:
|
||||||
print "Not connected to printer."
|
self.log("Not connected to printer.")
|
||||||
return
|
return
|
||||||
self.f = [i.replace("\n", "") for i in open(l.split()[0])]
|
self.f = [i.replace("\n", "") for i in open(l.split()[0])]
|
||||||
self.filename = l.split()[0]
|
self.filename = l.split()[0]
|
||||||
print "Loaded ", l, ", ", len(self.f)," lines."
|
self.log("Loaded ", l, ", ", len(self.f)," lines.")
|
||||||
tname = ""
|
tname = ""
|
||||||
if len(l.split())>1:
|
if len(l.split())>1:
|
||||||
tname = l.split()[1]
|
tname = l.split()[1]
|
||||||
else:
|
else:
|
||||||
print "please enter target name in 8.3 format."
|
self.log("please enter target name in 8.3 format.")
|
||||||
return
|
return
|
||||||
print "Uploading as ", tname
|
self.log("Uploading as ", tname)
|
||||||
print("Uploading "+self.filename)
|
self.log(("Uploading "+self.filename))
|
||||||
self.p.send_now("M28 "+tname)
|
self.p.send_now("M28 "+tname)
|
||||||
print("Press Ctrl-C to interrupt upload.")
|
self.log(("Press Ctrl-C to interrupt upload."))
|
||||||
self.p.startprint(self.f)
|
self.p.startprint(self.f)
|
||||||
try:
|
try:
|
||||||
sys.stdout.write("Progress: 00.0%")
|
sys.stdout.write("Progress: 00.0%")
|
||||||
|
@ -733,16 +740,16 @@ class pronsole(cmd.Cmd):
|
||||||
self.recvlisteners+=[self.listfiles]
|
self.recvlisteners+=[self.listfiles]
|
||||||
self.p.send_now("M20")
|
self.p.send_now("M20")
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
print "\b\b\b\b\b100%. Upload completed. ", tname, " should now be on the card."
|
self.log("\b\b\b\b\b100%. Upload completed. ", tname, " should now be on the card.")
|
||||||
return
|
return
|
||||||
except:
|
except:
|
||||||
print "...interrupted!"
|
self.log("...interrupted!")
|
||||||
self.p.pause()
|
self.p.pause()
|
||||||
self.p.send_now("M29 "+tname)
|
self.p.send_now("M29 "+tname)
|
||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
self.p.clear = 1
|
self.p.clear = 1
|
||||||
self.p.startprint([])
|
self.p.startprint([])
|
||||||
print "A partial file named ", tname, " may have been written to the sd card."
|
self.log("A partial file named ", tname, " may have been written to the sd card.")
|
||||||
|
|
||||||
|
|
||||||
def complete_upload(self, text, line, begidx, endidx):
|
def complete_upload(self, text, line, begidx, endidx):
|
||||||
|
@ -756,23 +763,23 @@ class pronsole(cmd.Cmd):
|
||||||
return glob.glob("*/")+glob.glob("*.g*")
|
return glob.glob("*/")+glob.glob("*.g*")
|
||||||
|
|
||||||
def help_upload(self):
|
def help_upload(self):
|
||||||
print "Uploads a gcode file to the sd card"
|
self.log("Uploads a gcode file to the sd card")
|
||||||
|
|
||||||
def help_print(self):
|
def help_print(self):
|
||||||
if self.f is None:
|
if self.f is None:
|
||||||
print "Send a loaded gcode file to the printer. Load a file with the load command first."
|
self.log("Send a loaded gcode file to the printer. Load a file with the load command first.")
|
||||||
else:
|
else:
|
||||||
print "Send a loaded gcode file to the printer. You have "+self.filename+" loaded right now."
|
self.log("Send a loaded gcode file to the printer. You have "+self.filename+" loaded right now.")
|
||||||
|
|
||||||
def do_print(self, l):
|
def do_print(self, l):
|
||||||
if self.f is None:
|
if self.f is None:
|
||||||
print "No file loaded. Please use load first."
|
self.log("No file loaded. Please use load first.")
|
||||||
return
|
return
|
||||||
if not self.p.online:
|
if not self.p.online:
|
||||||
print "Not connected to printer."
|
self.log("Not connected to printer.")
|
||||||
return
|
return
|
||||||
print("Printing "+self.filename)
|
self.log(("printing "+self.filename))
|
||||||
print("You can monitor the print with the monitor command.")
|
self.log(("You can monitor the print with the monitor command."))
|
||||||
self.p.startprint(self.f)
|
self.p.startprint(self.f)
|
||||||
#self.p.pause()
|
#self.p.pause()
|
||||||
#self.paused = True
|
#self.paused = True
|
||||||
|
@ -783,7 +790,7 @@ class pronsole(cmd.Cmd):
|
||||||
self.p.send_now("M25")
|
self.p.send_now("M25")
|
||||||
else:
|
else:
|
||||||
if(not self.p.printing):
|
if(not self.p.printing):
|
||||||
print "Not printing, cannot pause."
|
self.log("Not self.log(ing, cannot pause.")
|
||||||
return
|
return
|
||||||
self.p.pause()
|
self.p.pause()
|
||||||
#self.p.connect()# This seems to work, but is not a good solution.
|
#self.p.connect()# This seems to work, but is not a good solution.
|
||||||
|
@ -792,11 +799,11 @@ class pronsole(cmd.Cmd):
|
||||||
#self.do_resume(None)
|
#self.do_resume(None)
|
||||||
|
|
||||||
def help_pause(self):
|
def help_pause(self):
|
||||||
print "Pauses a running print"
|
self.log("Pauses a running print")
|
||||||
|
|
||||||
def do_resume(self, l):
|
def do_resume(self, l):
|
||||||
if not self.paused:
|
if not self.paused:
|
||||||
print "Not paused, unable to resume. Start a print first."
|
self.log("Not paused, unable to resume. Start a print first.")
|
||||||
return
|
return
|
||||||
self.paused = False
|
self.paused = False
|
||||||
if self.sdprinting:
|
if self.sdprinting:
|
||||||
|
@ -806,7 +813,7 @@ class pronsole(cmd.Cmd):
|
||||||
self.p.resume()
|
self.p.resume()
|
||||||
|
|
||||||
def help_resume(self):
|
def help_resume(self):
|
||||||
print "Resumes a paused print."
|
self.log("Resumes a paused print.")
|
||||||
|
|
||||||
def emptyline(self):
|
def emptyline(self):
|
||||||
pass
|
pass
|
||||||
|
@ -825,33 +832,33 @@ class pronsole(cmd.Cmd):
|
||||||
|
|
||||||
def do_ls(self, l):
|
def do_ls(self, l):
|
||||||
if not self.p.online:
|
if not self.p.online:
|
||||||
print "Printer is not online. Try connect to it first."
|
self.log("printer is not online. Try connect to it first.")
|
||||||
return
|
return
|
||||||
self.listing = 2
|
self.listing = 2
|
||||||
self.sdfiles = []
|
self.sdfiles = []
|
||||||
self.recvlisteners+=[self.listfiles]
|
self.recvlisteners+=[self.listfiles]
|
||||||
self.p.send_now("M20")
|
self.p.send_now("M20")
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
print " ".join(self.sdfiles)
|
self.log(" ".join(self.sdfiles))
|
||||||
|
|
||||||
def help_ls(self):
|
def help_ls(self):
|
||||||
print "lists files on the SD card"
|
self.log("lists files on the SD card")
|
||||||
|
|
||||||
def waitforsdresponse(self, l):
|
def waitforsdresponse(self, l):
|
||||||
if "file.open failed" in l:
|
if "file.open failed" in l:
|
||||||
print "Opening file failed."
|
self.log("Opening file failed.")
|
||||||
self.recvlisteners.remove(self.waitforsdresponse)
|
self.recvlisteners.remove(self.waitforsdresponse)
|
||||||
return
|
return
|
||||||
if "File opened" in l:
|
if "File opened" in l:
|
||||||
print l
|
self.log(l)
|
||||||
if "File selected" in l:
|
if "File selected" in l:
|
||||||
print "Starting print"
|
self.log("Starting print")
|
||||||
self.p.send_now("M24")
|
self.p.send_now("M24")
|
||||||
self.sdprinting = 1
|
self.sdprinting = 1
|
||||||
#self.recvlisteners.remove(self.waitforsdresponse)
|
#self.recvlisteners.remove(self.waitforsdresponse)
|
||||||
return
|
return
|
||||||
if "Done printing file" in l:
|
if "Done printing file" in l:
|
||||||
print l
|
self.log(l)
|
||||||
self.sdprinting = 0
|
self.sdprinting = 0
|
||||||
self.recvlisteners.remove(self.waitforsdresponse)
|
self.recvlisteners.remove(self.waitforsdresponse)
|
||||||
return
|
return
|
||||||
|
@ -868,11 +875,11 @@ class pronsole(cmd.Cmd):
|
||||||
self.p.reset()
|
self.p.reset()
|
||||||
|
|
||||||
def help_reset(self):
|
def help_reset(self):
|
||||||
print "Resets the printer."
|
self.log("Resets the printer.")
|
||||||
|
|
||||||
def do_sdprint(self, l):
|
def do_sdprint(self, l):
|
||||||
if not self.p.online:
|
if not self.p.online:
|
||||||
print "Printer is not online. Try connect to it first."
|
self.log("printer is not online. Try connect to it first.")
|
||||||
return
|
return
|
||||||
self.listing = 2
|
self.listing = 2
|
||||||
self.sdfiles = []
|
self.sdfiles = []
|
||||||
|
@ -880,17 +887,17 @@ class pronsole(cmd.Cmd):
|
||||||
self.p.send_now("M20")
|
self.p.send_now("M20")
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
if not (l.lower() in self.sdfiles):
|
if not (l.lower() in self.sdfiles):
|
||||||
print "File is not present on card. Upload it first"
|
self.log("File is not present on card. Upload it first")
|
||||||
return
|
return
|
||||||
self.recvlisteners+=[self.waitforsdresponse]
|
self.recvlisteners+=[self.waitforsdresponse]
|
||||||
self.p.send_now("M23 "+l.lower())
|
self.p.send_now("M23 "+l.lower())
|
||||||
print "Printing file: "+l.lower()+" from SD card."
|
self.log("printing file: "+l.lower()+" from SD card.")
|
||||||
print "Requesting SD print..."
|
self.log("Requesting SD print...")
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
def help_sdprint(self):
|
def help_sdprint(self):
|
||||||
print "Print a file from the SD card. Tabcompletes with available file names."
|
self.log("print a file from the SD card. Tabcompletes with available file names.")
|
||||||
print "sdprint filename.g"
|
self.log("sdprint filename.g")
|
||||||
|
|
||||||
def complete_sdprint(self, text, line, begidx, endidx):
|
def complete_sdprint(self, text, line, begidx, endidx):
|
||||||
if self.sdfiles==[] and self.p.online:
|
if self.sdfiles==[] and self.p.online:
|
||||||
|
@ -909,32 +916,32 @@ class pronsole(cmd.Cmd):
|
||||||
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):
|
||||||
if tstring[:5] == "echo:":
|
if tstring[:5] == "echo:":
|
||||||
tstring = tstring[5:].lstrip()
|
tstring = tstring[5:].lstrip()
|
||||||
print "\r" + tstring.ljust(15)
|
if self.silent == False: print "\r" + tstring.ljust(15)
|
||||||
sys.stdout.write(self.promptf())
|
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)
|
||||||
|
|
||||||
def help_shell(self):
|
def help_shell(self):
|
||||||
print "Executes a python command. Example:"
|
self.log("Executes a python command. Example:")
|
||||||
print "! os.listdir('.')"
|
self.log("! os.listdir('.')")
|
||||||
|
|
||||||
def default(self, l):
|
def default(self, l):
|
||||||
if(l[0] in self.commandprefixes.upper()):
|
if(l[0] in self.commandprefixes.upper()):
|
||||||
if(self.p and self.p.online):
|
if(self.p and self.p.online):
|
||||||
if(not self.p.loud):
|
if(not self.p.loud):
|
||||||
print "SENDING:"+l
|
self.log("SENDING:"+l)
|
||||||
self.p.send_now(l)
|
self.p.send_now(l)
|
||||||
else:
|
else:
|
||||||
print "Printer is not online."
|
self.log("printer is not online.")
|
||||||
return
|
return
|
||||||
elif(l[0] in self.commandprefixes.lower()):
|
elif(l[0] in self.commandprefixes.lower()):
|
||||||
if(self.p and self.p.online):
|
if(self.p and self.p.online):
|
||||||
if(not self.p.loud):
|
if(not self.p.loud):
|
||||||
print "SENDING:"+l.upper()
|
self.log("SENDING:"+l.upper())
|
||||||
self.p.send_now(l.upper())
|
self.p.send_now(l.upper())
|
||||||
else:
|
else:
|
||||||
print "Printer is not online."
|
self.log("printer is not online.")
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
cmd.Cmd.default(self, l)
|
cmd.Cmd.default(self, l)
|
||||||
|
@ -942,6 +949,10 @@ 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:
|
||||||
|
self.log(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:
|
if "dynamic" in l:
|
||||||
self.dynamic_temp = True
|
self.dynamic_temp = True
|
||||||
|
@ -955,7 +966,7 @@ class pronsole(cmd.Cmd):
|
||||||
print "Bed: %s/%s" % (self.status.bed_temp, self.status.bed_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."
|
self.log("Read the extruder and bed temperature.")
|
||||||
|
|
||||||
def do_settemp(self, l):
|
def do_settemp(self, l):
|
||||||
try:
|
try:
|
||||||
|
@ -970,18 +981,18 @@ class pronsole(cmd.Cmd):
|
||||||
return
|
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."
|
self.log("Setting hotend temperature to ", f, " degrees Celsius.")
|
||||||
else:
|
else:
|
||||||
print "Printer is not online."
|
self.log("printer is not online.")
|
||||||
else:
|
else:
|
||||||
print "You cannot set negative temperatures. To turn the hotend off entirely, set its temperature to 0."
|
self.log("You cannot set negative temperatures. To turn the hotend off entirely, set its temperature to 0.")
|
||||||
except:
|
except:
|
||||||
print "You must enter a temperature."
|
self.log("You must enter a temperature.")
|
||||||
|
|
||||||
def help_settemp(self):
|
def help_settemp(self):
|
||||||
print "Sets the hotend temperature to the value entered."
|
self.log("Sets the hotend temperature to the value entered.")
|
||||||
print "Enter either a temperature in celsius or one of the following keywords"
|
self.log("Enter either a temperature in celsius or one of the following keywords")
|
||||||
print ", ".join([i+"("+self.temps[i]+")" for i in self.temps.keys()])
|
self.log(", ".join([i+"("+self.temps[i]+")" for i in self.temps.keys()]))
|
||||||
|
|
||||||
def complete_settemp(self, text, line, begidx, endidx):
|
def complete_settemp(self, text, line, begidx, endidx):
|
||||||
if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1]==" "):
|
if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1]==" "):
|
||||||
|
@ -996,18 +1007,18 @@ class pronsole(cmd.Cmd):
|
||||||
if f>=0:
|
if f>=0:
|
||||||
if self.p.online:
|
if self.p.online:
|
||||||
self.p.send_now("M140 S"+l)
|
self.p.send_now("M140 S"+l)
|
||||||
print "Setting bed temperature to ", f, " degrees Celsius."
|
self.log("Setting bed temperature to ", f, " degrees Celsius.")
|
||||||
else:
|
else:
|
||||||
print "Printer is not online."
|
self.log("printer is not online.")
|
||||||
else:
|
else:
|
||||||
print "You cannot set negative temperatures. To turn the bed off entirely, set its temperature to 0."
|
self.log("You cannot set negative temperatures. To turn the bed off entirely, set its temperature to 0.")
|
||||||
except:
|
except:
|
||||||
print "You must enter a temperature."
|
self.log("You must enter a temperature.")
|
||||||
|
|
||||||
def help_bedtemp(self):
|
def help_bedtemp(self):
|
||||||
print "Sets the bed temperature to the value entered."
|
self.log("Sets the bed temperature to the value entered.")
|
||||||
print "Enter either a temperature in celsius or one of the following keywords"
|
self.log("Enter either a temperature in celsius or one of the following keywords")
|
||||||
print ", ".join([i+"("+self.bedtemps[i]+")" for i in self.bedtemps.keys()])
|
self.log(", ".join([i+"("+self.bedtemps[i]+")" for i in self.bedtemps.keys()]))
|
||||||
|
|
||||||
def complete_bedtemp(self, text, line, begidx, endidx):
|
def complete_bedtemp(self, text, line, begidx, endidx):
|
||||||
if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1]==" "):
|
if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1]==" "):
|
||||||
|
@ -1015,13 +1026,13 @@ class pronsole(cmd.Cmd):
|
||||||
|
|
||||||
def do_move(self, l):
|
def do_move(self, l):
|
||||||
if(len(l.split())<2):
|
if(len(l.split())<2):
|
||||||
print "No move specified."
|
self.log("No move specified.")
|
||||||
return
|
return
|
||||||
if self.p.printing:
|
if self.p.printing:
|
||||||
print "Printer is currently printing. Please pause the print before you issue manual commands."
|
self.log("printer is currently printing. Please pause the print before you issue manual commands.")
|
||||||
return
|
return
|
||||||
if not self.p.online:
|
if not self.p.online:
|
||||||
print "Printer is not online. Unable to move."
|
self.log("printer is not online. Unable to move.")
|
||||||
return
|
return
|
||||||
l = l.split()
|
l = l.split()
|
||||||
if(l[0].lower()=="x"):
|
if(l[0].lower()=="x"):
|
||||||
|
@ -1037,13 +1048,13 @@ class pronsole(cmd.Cmd):
|
||||||
feed = self.settings.e_feedrate
|
feed = self.settings.e_feedrate
|
||||||
axis = "E"
|
axis = "E"
|
||||||
else:
|
else:
|
||||||
print "Unknown axis."
|
self.log("Unknown axis.")
|
||||||
return
|
return
|
||||||
dist = 0
|
dist = 0
|
||||||
try:
|
try:
|
||||||
dist = float(l[1])
|
dist = float(l[1])
|
||||||
except:
|
except:
|
||||||
print "Invalid distance"
|
self.log("Invalid distance")
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
feed = int(l[2])
|
feed = int(l[2])
|
||||||
|
@ -1054,11 +1065,11 @@ class pronsole(cmd.Cmd):
|
||||||
self.p.send_now("G90")
|
self.p.send_now("G90")
|
||||||
|
|
||||||
def help_move(self):
|
def help_move(self):
|
||||||
print "Move an axis. Specify the name of the axis and the amount. "
|
self.log("Move an axis. Specify the name of the axis and the amount. ")
|
||||||
print "move X 10 will move the X axis forward by 10mm at ", self.settings.xy_feedrate, "mm/min (default XY speed)"
|
self.log("move X 10 will move the X axis forward by 10mm at ", self.settings.xy_feedrate, "mm/min (default XY speed)")
|
||||||
print "move Y 10 5000 will move the Y axis forward by 10mm at 5000mm/min"
|
self.log("move Y 10 5000 will move the Y axis forward by 10mm at 5000mm/min")
|
||||||
print "move Z -1 will move the Z axis down by 1mm at ", self.settings.z_feedrate, "mm/min (default Z speed)"
|
self.log("move Z -1 will move the Z axis down by 1mm at ", self.settings.z_feedrate, "mm/min (default Z speed)")
|
||||||
print "Common amounts are in the tabcomplete list."
|
self.log("Common amounts are in the tabcomplete list.")
|
||||||
|
|
||||||
def complete_move(self, text, line, begidx, endidx):
|
def complete_move(self, text, line, begidx, endidx):
|
||||||
if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1]==" "):
|
if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1]==" "):
|
||||||
|
@ -1078,29 +1089,29 @@ class pronsole(cmd.Cmd):
|
||||||
length = 5#default extrusion length
|
length = 5#default extrusion length
|
||||||
feed = self.settings.e_feedrate#default speed
|
feed = self.settings.e_feedrate#default speed
|
||||||
if not self.p.online:
|
if not self.p.online:
|
||||||
print "Printer is not online. Unable to move."
|
self.log("printer is not online. Unable to move.")
|
||||||
return
|
return
|
||||||
if self.p.printing:
|
if self.p.printing:
|
||||||
print "Printer is currently printing. Please pause the print before you issue manual commands."
|
self.log("printer is currently printing. Please pause the print before you issue manual commands.")
|
||||||
return
|
return
|
||||||
ls = l.split()
|
ls = l.split()
|
||||||
if len(ls):
|
if len(ls):
|
||||||
try:
|
try:
|
||||||
length = float(ls[0])
|
length = float(ls[0])
|
||||||
except:
|
except:
|
||||||
print "Invalid length given."
|
self.log("Invalid length given.")
|
||||||
if len(ls)>1:
|
if len(ls)>1:
|
||||||
try:
|
try:
|
||||||
feed = int(ls[1])
|
feed = int(ls[1])
|
||||||
except:
|
except:
|
||||||
print "Invalid speed given."
|
self.log("Invalid speed given.")
|
||||||
if override is not None:
|
if override is not None:
|
||||||
length = override
|
length = override
|
||||||
feed = overridefeed
|
feed = overridefeed
|
||||||
if length > 0:
|
if length > 0:
|
||||||
print "Extruding %fmm of filament."%(length,)
|
self.log("Extruding %fmm of filament."%(length,))
|
||||||
elif length <0:
|
elif length <0:
|
||||||
print "Reversing %fmm of filament."%(-1*length,)
|
self.log("Reversing %fmm of filament."%(-1*length,))
|
||||||
else:
|
else:
|
||||||
"Length is 0, not doing anything."
|
"Length is 0, not doing anything."
|
||||||
self.p.send_now("G91")
|
self.p.send_now("G91")
|
||||||
|
@ -1108,40 +1119,40 @@ class pronsole(cmd.Cmd):
|
||||||
self.p.send_now("G90")
|
self.p.send_now("G90")
|
||||||
|
|
||||||
def help_extrude(self):
|
def help_extrude(self):
|
||||||
print "Extrudes a length of filament, 5mm by default, or the number of mm given as a parameter"
|
self.log("Extrudes a length of filament, 5mm by default, or the number of mm given as a parameter")
|
||||||
print "extrude - extrudes 5mm of filament at 300mm/min (5mm/s)"
|
self.log("extrude - extrudes 5mm of filament at 300mm/min (5mm/s)")
|
||||||
print "extrude 20 - extrudes 20mm of filament at 300mm/min (5mm/s)"
|
self.log("extrude 20 - extrudes 20mm of filament at 300mm/min (5mm/s)")
|
||||||
print "extrude -5 - REVERSES 5mm of filament at 300mm/min (5mm/s)"
|
self.log("extrude -5 - REVERSES 5mm of filament at 300mm/min (5mm/s)")
|
||||||
print "extrude 10 210 - extrudes 10mm of filament at 210mm/min (3.5mm/s)"
|
self.log("extrude 10 210 - extrudes 10mm of filament at 210mm/min (3.5mm/s)")
|
||||||
|
|
||||||
def do_reverse(self, l):
|
def do_reverse(self, l):
|
||||||
length = 5#default extrusion length
|
length = 5#default extrusion length
|
||||||
feed = self.settings.e_feedrate#default speed
|
feed = self.settings.e_feedrate#default speed
|
||||||
if not self.p.online:
|
if not self.p.online:
|
||||||
print "Printer is not online. Unable to move."
|
self.log("printer is not online. Unable to move.")
|
||||||
return
|
return
|
||||||
if self.p.printing:
|
if self.p.printing:
|
||||||
print "Printer is currently printing. Please pause the print before you issue manual commands."
|
self.log("printer is currently printing. Please pause the print before you issue manual commands.")
|
||||||
return
|
return
|
||||||
ls = l.split()
|
ls = l.split()
|
||||||
if len(ls):
|
if len(ls):
|
||||||
try:
|
try:
|
||||||
length = float(ls[0])
|
length = float(ls[0])
|
||||||
except:
|
except:
|
||||||
print "Invalid length given."
|
self.log("Invalid length given.")
|
||||||
if len(ls)>1:
|
if len(ls)>1:
|
||||||
try:
|
try:
|
||||||
feed = int(ls[1])
|
feed = int(ls[1])
|
||||||
except:
|
except:
|
||||||
print "Invalid speed given."
|
self.log("Invalid speed given.")
|
||||||
self.do_extrude("", length*-1.0, feed)
|
self.do_extrude("", length*-1.0, feed)
|
||||||
|
|
||||||
def help_reverse(self):
|
def help_reverse(self):
|
||||||
print "Reverses the extruder, 5mm by default, or the number of mm given as a parameter"
|
self.log("Reverses the extruder, 5mm by default, or the number of mm given as a parameter")
|
||||||
print "reverse - reverses 5mm of filament at 300mm/min (5mm/s)"
|
self.log("reverse - reverses 5mm of filament at 300mm/min (5mm/s)")
|
||||||
print "reverse 20 - reverses 20mm of filament at 300mm/min (5mm/s)"
|
self.log("reverse 20 - reverses 20mm of filament at 300mm/min (5mm/s)")
|
||||||
print "reverse 10 210 - extrudes 10mm of filament at 210mm/min (3.5mm/s)"
|
self.log("reverse 10 210 - extrudes 10mm of filament at 210mm/min (3.5mm/s)")
|
||||||
print "reverse -5 - EXTRUDES 5mm of filament at 300mm/min (5mm/s)"
|
self.log("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:
|
if self.status.extruder_temp_target != 0:
|
||||||
|
@ -1151,35 +1162,35 @@ class pronsole(cmd.Cmd):
|
||||||
if self.status.bed_temp_taret != 0:
|
if self.status.bed_temp_taret != 0:
|
||||||
print "Setting bed temp to 0"
|
print "Setting bed temp to 0"
|
||||||
self.p.send_now("M140 S0.0")
|
self.p.send_now("M140 S0.0")
|
||||||
print "Disconnecting from printer..."
|
self.log("Disconnecting from printer...")
|
||||||
print self.p.printing
|
print self.p.printing
|
||||||
if self.p.printing:
|
if self.p.printing:
|
||||||
print "Are you sure you want to exit while printing?"
|
print "Are you sure you want to exit while printing?"
|
||||||
print "(this will terminate the print)."
|
print "(this will terminate the print)."
|
||||||
if not confirm():
|
if not confirm():
|
||||||
return False
|
return False
|
||||||
print "Exiting program. Goodbye!"
|
self.log("Exiting program. Goodbye!")
|
||||||
self.p.disconnect()
|
self.p.disconnect()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def help_exit(self):
|
def help_exit(self):
|
||||||
print "Disconnects from the printer and exits the program."
|
self.log("Disconnects from the printer and exits the program.")
|
||||||
|
|
||||||
def do_monitor(self, l):
|
def do_monitor(self, l):
|
||||||
interval = 5
|
interval = 5
|
||||||
if not self.p.online:
|
if not self.p.online:
|
||||||
print "Printer is not online. Please connect first."
|
self.log("printer is not online. Please connect first.")
|
||||||
return
|
return
|
||||||
if not (self.p.printing or self.sdprinting):
|
if not (self.p.printing or self.sdprinting):
|
||||||
print "Printer not printing. Please print something before monitoring."
|
self.log("Printer not printing. Please print something before monitoring.")
|
||||||
return
|
return
|
||||||
print "Monitoring printer, use ^C to interrupt."
|
self.log("Monitoring printer, use ^C to interrupt.")
|
||||||
if len(l):
|
if len(l):
|
||||||
try:
|
try:
|
||||||
interval = float(l)
|
interval = float(l)
|
||||||
except:
|
except:
|
||||||
print "Invalid period given."
|
self.log("Invalid period given.")
|
||||||
print "Updating values every %f seconds."%(interval,)
|
self.log("Updating values every %f seconds."%(interval,))
|
||||||
self.monitoring = 1
|
self.monitoring = 1
|
||||||
prev_msg_len = 0
|
prev_msg_len = 0
|
||||||
try:
|
try:
|
||||||
|
@ -1197,17 +1208,18 @@ class pronsole(cmd.Cmd):
|
||||||
progress = self.percentdone
|
progress = self.percentdone
|
||||||
progress = int(progress*10)/10.0 #limit precision
|
progress = int(progress*10)/10.0 #limit precision
|
||||||
prev_msg = preface + str(progress) + "%"
|
prev_msg = preface + str(progress) + "%"
|
||||||
sys.stdout.write("\r" + prev_msg.ljust(prev_msg_len))
|
if self.silent == False:
|
||||||
sys.stdout.flush()
|
sys.stdout.write("\r" + prev_msg.ljust(prev_msg_len))
|
||||||
|
sys.stdout.flush()
|
||||||
prev_msg_len = len(prev_msg)
|
prev_msg_len = len(prev_msg)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print "Done monitoring."
|
if self.silent == False: print "Done monitoring."
|
||||||
self.monitoring = 0
|
self.monitoring = 0
|
||||||
|
|
||||||
def help_monitor(self):
|
def help_monitor(self):
|
||||||
print "Monitor a machine's temperatures and an SD print's status."
|
self.log("Monitor a machine's temperatures and an SD print's status.")
|
||||||
print "monitor - Reports temperature and SD print status (if SD printing) every 5 seconds"
|
self.log("monitor - Reports temperature and SD print status (if SD printing) every 5 seconds")
|
||||||
print "monitor 2 - Reports temperature and SD print status (if SD printing) every 2 seconds"
|
self.log("monitor 2 - Reports temperature and SD print status (if SD printing) every 2 seconds")
|
||||||
|
|
||||||
def expandcommand(self, c):
|
def expandcommand(self, c):
|
||||||
return c.replace("$python", sys.executable)
|
return c.replace("$python", sys.executable)
|
||||||
|
@ -1215,31 +1227,31 @@ class pronsole(cmd.Cmd):
|
||||||
def do_skein(self, l):
|
def do_skein(self, l):
|
||||||
l = l.split()
|
l = l.split()
|
||||||
if len(l) == 0:
|
if len(l) == 0:
|
||||||
print "No file name given."
|
self.log("No file name given.")
|
||||||
return
|
return
|
||||||
settings = 0
|
settings = 0
|
||||||
if(l[0]=="set"):
|
if(l[0]=="set"):
|
||||||
settings = 1
|
settings = 1
|
||||||
else:
|
else:
|
||||||
print "Skeining file:"+l[0]
|
self.log("Skeining file:"+l[0])
|
||||||
if not(os.path.exists(l[0])):
|
if not(os.path.exists(l[0])):
|
||||||
print "File not found!"
|
self.log("File not found!")
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
import shlex
|
import shlex
|
||||||
if(settings):
|
if(settings):
|
||||||
param = self.expandcommand(self.settings.sliceoptscommand).replace("\\", "\\\\").encode()
|
param = self.expandcommand(self.settings.sliceoptscommand).replace("\\", "\\\\").encode()
|
||||||
print "Entering slicer settings: ", param
|
self.log("Entering slicer settings: ", param)
|
||||||
subprocess.call(shlex.split(param))
|
subprocess.call(shlex.split(param))
|
||||||
else:
|
else:
|
||||||
param = self.expandcommand(self.settings.slicecommand).encode()
|
param = self.expandcommand(self.settings.slicecommand).encode()
|
||||||
print "Slicing: ", param
|
self.log("Slicing: ", param)
|
||||||
params = [i.replace("$s", l[0]).replace("$o", l[0].replace(".stl", "_export.gcode").replace(".STL", "_export.gcode")).encode() for i in shlex.split(param.replace("\\", "\\\\").encode())]
|
params = [i.replace("$s", l[0]).replace("$o", l[0].replace(".stl", "_export.gcode").replace(".STL", "_export.gcode")).encode() for i in shlex.split(param.replace("\\", "\\\\").encode())]
|
||||||
subprocess.call(params)
|
subprocess.call(params)
|
||||||
print "Loading sliced file."
|
self.log("Loading sliced file.")
|
||||||
self.do_load(l[0].replace(".stl", "_export.gcode"))
|
self.do_load(l[0].replace(".stl", "_export.gcode"))
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
print "Skeinforge execution failed: ", e
|
self.log("Skeinforge execution failed: ", e)
|
||||||
|
|
||||||
def complete_skein(self, text, line, begidx, endidx):
|
def complete_skein(self, text, line, begidx, endidx):
|
||||||
s = line.split()
|
s = line.split()
|
||||||
|
@ -1252,18 +1264,18 @@ class pronsole(cmd.Cmd):
|
||||||
return glob.glob("*/")+glob.glob("*.stl")
|
return glob.glob("*/")+glob.glob("*.stl")
|
||||||
|
|
||||||
def help_skein(self):
|
def help_skein(self):
|
||||||
print "Creates a gcode file from an stl model using the slicer (with tab-completion)"
|
self.log("Creates a gcode file from an stl model using the slicer (with tab-completion)")
|
||||||
print "skein filename.stl - create gcode file"
|
self.log("skein filename.stl - create gcode file")
|
||||||
print "skein filename.stl view - create gcode file and view using skeiniso"
|
self.log("skein filename.stl view - create gcode file and view using skeiniso")
|
||||||
print "skein set - adjust slicer settings"
|
self.log("skein set - adjust slicer settings")
|
||||||
|
|
||||||
|
|
||||||
def do_home(self, l):
|
def do_home(self, l):
|
||||||
if not self.p.online:
|
if not self.p.online:
|
||||||
print "Printer is not online. Unable to move."
|
self.log("printer is not online. Unable to move.")
|
||||||
return
|
return
|
||||||
if self.p.printing:
|
if self.p.printing:
|
||||||
print "Printer is currently printing. Please pause the print before you issue manual commands."
|
self.log("printer is currently printing. Please pause the print before you issue manual commands.")
|
||||||
return
|
return
|
||||||
if "x" in l.lower():
|
if "x" in l.lower():
|
||||||
self.p.send_now("G28 X0")
|
self.p.send_now("G28 X0")
|
||||||
|
@ -1278,32 +1290,26 @@ class pronsole(cmd.Cmd):
|
||||||
self.p.send_now("G92 E0")
|
self.p.send_now("G92 E0")
|
||||||
|
|
||||||
def help_home(self):
|
def help_home(self):
|
||||||
print "Homes the printer"
|
self.log("Homes the printer")
|
||||||
print "home - homes all axes and zeroes the extruder(Using G28 and G92)"
|
self.log("home - homes all axes and zeroes the extruder(Using G28 and G92)")
|
||||||
print "home xy - homes x and y axes (Using G28)"
|
self.log("home xy - homes x and y axes (Using G28)")
|
||||||
print "home z - homes z axis only (Using G28)"
|
self.log("home z - homes z axis only (Using G28)")
|
||||||
print "home e - set extruder position to zero (Using G92)"
|
self.log("home e - set extruder position to zero (Using G92)")
|
||||||
print "home xyze - homes all axes and zeroes the extruder (Using G28 and G92)"
|
self.log("home xyze - homes all axes and zeroes the extruder (Using G28 and G92)")
|
||||||
|
|
||||||
def parse_cmdline(self, args):
|
def parse_cmdline(self, args):
|
||||||
import getopt
|
import getopt
|
||||||
opts, args = getopt.getopt(args, "c:e:hw", ["conf = ", "config = ", "help", "web", "web-config = ", "web-auth-config = "])
|
opts, args = getopt.getopt(args, "c:e:hw", ["conf = ", "config = ", "help"])
|
||||||
for o, a in opts:
|
for o, a in opts:
|
||||||
#print repr((o, a))
|
#self.log(repr((o, a)))
|
||||||
if o in ("-c", "--conf", "--config"):
|
if o in ("-c", "--conf", "--config"):
|
||||||
self.load_rc(a)
|
self.load_rc(a)
|
||||||
elif o in ("-w", "--web"):
|
|
||||||
self.webrequested = True
|
|
||||||
elif o == "--web-config":
|
|
||||||
self.web_config = a
|
|
||||||
elif o == "--web-auth-config":
|
|
||||||
self.web_auth_config = a
|
|
||||||
elif o in ("-h", "--help"):
|
elif o in ("-h", "--help"):
|
||||||
print "Usage: "+sys.argv[0]+' [-c filename [-c filename2 ... ] ] [-e "command" ...]'
|
self.log("Usage: "+sys.argv[0]+' [-c filename [-c filename2 ... ] ] [-e "command" ...]')
|
||||||
print " -c | --conf | --config - override startup .pronsolerc file"
|
self.log(" -c | --conf | --config - override startup .pronsolerc file")
|
||||||
print " may chain config files, settings auto-save will go into last file in the chain"
|
self.log(" may chain config files, settings auto-save will go into last file in the chain")
|
||||||
print ' -e <command> - executes command after configuration/.pronsolerc is loaded'
|
self.log(' -e <command> - executes command after configuration/.pronsolerc is loaded')
|
||||||
print " macros/settings from these commands are not autosaved"
|
self.log(" macros/settings from these commands are not autosaved")
|
||||||
sys.exit()
|
sys.exit()
|
||||||
if not self.rc_loaded:
|
if not self.rc_loaded:
|
||||||
self.load_default_rc()
|
self.load_default_rc()
|
||||||
|
|
|
@ -196,21 +196,6 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
||||||
self.predisconnect_layer = None
|
self.predisconnect_layer = None
|
||||||
self.hsetpoint = 0.0
|
self.hsetpoint = 0.0
|
||||||
self.bsetpoint = 0.0
|
self.bsetpoint = 0.0
|
||||||
self.webInterface = None
|
|
||||||
if self.webrequested:
|
|
||||||
try :
|
|
||||||
import cherrypy
|
|
||||||
from printrun import webinterface
|
|
||||||
try:
|
|
||||||
self.webInterface = webinterface.WebInterface(self)
|
|
||||||
self.webThread = threading.Thread(target = webinterface.StartWebInterfaceThread, args = (self.webInterface, ))
|
|
||||||
self.webThread.start()
|
|
||||||
except:
|
|
||||||
print _("Failed to start web interface")
|
|
||||||
traceback.print_exc(file = sys.stdout)
|
|
||||||
self.webInterface = None
|
|
||||||
except:
|
|
||||||
print _("CherryPy is not installed. Web Interface Disabled.")
|
|
||||||
if self.filename is not None:
|
if self.filename is not None:
|
||||||
self.do_load(self.filename)
|
self.do_load(self.filename)
|
||||||
|
|
||||||
|
@ -364,8 +349,6 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
||||||
print _("You cannot set negative temperatures. To turn the hotend off entirely, set its temperature to 0.")
|
print _("You cannot set negative temperatures. To turn the hotend off entirely, set its temperature to 0.")
|
||||||
except Exception, x:
|
except Exception, x:
|
||||||
print _("You must enter a temperature. (%s)") % (repr(x),)
|
print _("You must enter a temperature. (%s)") % (repr(x),)
|
||||||
if self.webInterface:
|
|
||||||
self.webInterface.AddLog("You must enter a temperature. (%s)" % (repr(x),))
|
|
||||||
|
|
||||||
def do_bedtemp(self, l = ""):
|
def do_bedtemp(self, l = ""):
|
||||||
try:
|
try:
|
||||||
|
@ -382,16 +365,10 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
||||||
self.setbedgui(f)
|
self.setbedgui(f)
|
||||||
else:
|
else:
|
||||||
print _("Printer is not online.")
|
print _("Printer is not online.")
|
||||||
if self.webInterface:
|
|
||||||
self.webInterface.AddLog("Printer is not online.")
|
|
||||||
else:
|
else:
|
||||||
print _("You cannot set negative temperatures. To turn the bed off entirely, set its temperature to 0.")
|
print _("You cannot set negative temperatures. To turn the bed off entirely, set its temperature to 0.")
|
||||||
if self.webInterface:
|
|
||||||
self.webInterface.AddLog("You cannot set negative temperatures. To turn the bed off entirely, set its temperature to 0.")
|
|
||||||
except Exception, x:
|
except Exception, x:
|
||||||
print _("You must enter a temperature. (%s)") % (repr(x),)
|
print _("You must enter a temperature. (%s)") % (repr(x),)
|
||||||
if self.webInterface:
|
|
||||||
self.webInterface.AddLog("You must enter a temperature.")
|
|
||||||
|
|
||||||
def end_macro(self):
|
def end_macro(self):
|
||||||
pronsole.pronsole.end_macro(self)
|
pronsole.pronsole.end_macro(self)
|
||||||
|
@ -411,8 +388,6 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
||||||
self.delete_macro(macro_name)
|
self.delete_macro(macro_name)
|
||||||
return
|
return
|
||||||
print _("Cancelled.")
|
print _("Cancelled.")
|
||||||
if self.webInterface:
|
|
||||||
self.webInterface.AddLog("Cancelled.")
|
|
||||||
return
|
return
|
||||||
self.cur_macro_name = macro_name
|
self.cur_macro_name = macro_name
|
||||||
self.cur_macro_def = definition
|
self.cur_macro_def = definition
|
||||||
|
@ -452,8 +427,6 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
||||||
projectlayer.setframe(self,self.p).Show()
|
projectlayer.setframe(self,self.p).Show()
|
||||||
else:
|
else:
|
||||||
print _("Printer is not online.")
|
print _("Printer is not online.")
|
||||||
if self.webInterface:
|
|
||||||
self.webInterface.AddLog("Printer is not online.")
|
|
||||||
|
|
||||||
def popmenu(self):
|
def popmenu(self):
|
||||||
self.menustrip = wx.MenuBar()
|
self.menustrip = wx.MenuBar()
|
||||||
|
@ -530,8 +503,6 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
||||||
old_def = self.macros[macro]
|
old_def = self.macros[macro]
|
||||||
elif len([c for c in macro.encode("ascii", "replace") if not c.isalnum() and c != "_"]):
|
elif len([c for c in macro.encode("ascii", "replace") if not c.isalnum() and c != "_"]):
|
||||||
print _("Macro name may contain only ASCII alphanumeric symbols and underscores")
|
print _("Macro name may contain only ASCII alphanumeric symbols and underscores")
|
||||||
if self.webInterface:
|
|
||||||
self.webInterface.AddLog("Macro name may contain only alphanumeric symbols and underscores")
|
|
||||||
return
|
return
|
||||||
elif hasattr(self.__class__, "do_"+macro):
|
elif hasattr(self.__class__, "do_"+macro):
|
||||||
print _("Name '%s' is being used by built-in command") % macro
|
print _("Name '%s' is being used by built-in command") % macro
|
||||||
|
@ -713,8 +684,6 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
||||||
|
|
||||||
def help_button(self):
|
def help_button(self):
|
||||||
print _('Defines custom button. Usage: button <num> "title" [/c "colour"] command')
|
print _('Defines custom button. Usage: button <num> "title" [/c "colour"] command')
|
||||||
if self.webInterface:
|
|
||||||
self.webInterface.AddLog('Defines custom button. Usage: button <num> "title" [/c "colour"] command')
|
|
||||||
|
|
||||||
def do_button(self, argstr):
|
def do_button(self, argstr):
|
||||||
def nextarg(rest):
|
def nextarg(rest):
|
||||||
|
@ -737,8 +706,6 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
||||||
command = argstr.strip()
|
command = argstr.strip()
|
||||||
if num<0 or num>=64:
|
if num<0 or num>=64:
|
||||||
print _("Custom button number should be between 0 and 63")
|
print _("Custom button number should be between 0 and 63")
|
||||||
if self.webInterface:
|
|
||||||
self.webInterface.AddLog("Custom button number should be between 0 and 63")
|
|
||||||
return
|
return
|
||||||
while num >= len(self.custombuttons):
|
while num >= len(self.custombuttons):
|
||||||
self.custombuttons.append(None)
|
self.custombuttons.append(None)
|
||||||
|
@ -1004,8 +971,6 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
||||||
self.cur_button = None
|
self.cur_button = None
|
||||||
except:
|
except:
|
||||||
print _("event object missing")
|
print _("event object missing")
|
||||||
if self.webInterface:
|
|
||||||
self.webInterface.AddLog("event object missing")
|
|
||||||
self.cur_button = None
|
self.cur_button = None
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
@ -1025,9 +990,6 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
self.Destroy()
|
self.Destroy()
|
||||||
if self.webInterface:
|
|
||||||
from printrun import webinterface
|
|
||||||
webinterface.KillWebInterfaceThread()
|
|
||||||
|
|
||||||
def do_monitor(self, l = ""):
|
def do_monitor(self, l = ""):
|
||||||
if l.strip()=="":
|
if l.strip()=="":
|
||||||
|
@ -1040,17 +1002,11 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
||||||
wx.CallAfter(self.monitorbox.SetValue, self.monitor_interval>0)
|
wx.CallAfter(self.monitorbox.SetValue, self.monitor_interval>0)
|
||||||
except:
|
except:
|
||||||
print _("Invalid period given.")
|
print _("Invalid period given.")
|
||||||
if self.webInterface:
|
|
||||||
self.webInterface.AddLog("Invalid period given.")
|
|
||||||
self.setmonitor(None)
|
self.setmonitor(None)
|
||||||
if self.monitor:
|
if self.monitor:
|
||||||
print _("Monitoring printer.")
|
print _("Monitoring printer.")
|
||||||
if self.webInterface:
|
|
||||||
self.webInterface.AddLog("Monitoring printer.")
|
|
||||||
else:
|
else:
|
||||||
print _("Done monitoring.")
|
print _("Done monitoring.")
|
||||||
if self.webInterface:
|
|
||||||
self.webInterface.AddLog("Done monitoring.")
|
|
||||||
|
|
||||||
def setmonitor(self, e):
|
def setmonitor(self, e):
|
||||||
self.monitor = self.monitorbox.GetValue()
|
self.monitor = self.monitorbox.GetValue()
|
||||||
|
@ -1065,8 +1021,6 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
||||||
except:
|
except:
|
||||||
print "attempted to write invalid text to console"
|
print "attempted to write invalid text to console"
|
||||||
pass
|
pass
|
||||||
if self.webInterface:
|
|
||||||
self.webInterface.AppendLog(text)
|
|
||||||
|
|
||||||
def setloud(self,e):
|
def setloud(self,e):
|
||||||
self.p.loud=e.IsChecked()
|
self.p.loud=e.IsChecked()
|
||||||
|
@ -1229,8 +1183,6 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
||||||
import shlex
|
import shlex
|
||||||
param = self.expandcommand(self.settings.slicecommand).encode()
|
param = self.expandcommand(self.settings.slicecommand).encode()
|
||||||
print "Slicing: ", param
|
print "Slicing: ", param
|
||||||
if self.webInterface:
|
|
||||||
self.webInterface.AddLog("Slicing: "+param)
|
|
||||||
pararray = [i.replace("$s", self.filename).replace("$o", self.filename.replace(".stl", "_export.gcode").replace(".STL", "_export.gcode")).encode() for i in shlex.split(param.replace("\\", "\\\\").encode())]
|
pararray = [i.replace("$s", self.filename).replace("$o", self.filename.replace(".stl", "_export.gcode").replace(".STL", "_export.gcode")).encode() for i in shlex.split(param.replace("\\", "\\\\").encode())]
|
||||||
#print pararray
|
#print pararray
|
||||||
self.skeinp = subprocess.Popen(pararray, stderr = subprocess.STDOUT, stdout = subprocess.PIPE)
|
self.skeinp = subprocess.Popen(pararray, stderr = subprocess.STDOUT, stdout = subprocess.PIPE)
|
||||||
|
@ -1242,8 +1194,6 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
||||||
self.stopsf = 1
|
self.stopsf = 1
|
||||||
except:
|
except:
|
||||||
print _("Failed to execute slicing software: ")
|
print _("Failed to execute slicing software: ")
|
||||||
if self.webInterface:
|
|
||||||
self.webInterface.AddLog("Failed to execute slicing software: ")
|
|
||||||
self.stopsf = 1
|
self.stopsf = 1
|
||||||
traceback.print_exc(file = sys.stdout)
|
traceback.print_exc(file = sys.stdout)
|
||||||
|
|
||||||
|
@ -1336,8 +1286,6 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
||||||
Xtot, Ytot, Ztot, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax = pronsole.measurements(self.f)
|
Xtot, Ytot, Ztot, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax = pronsole.measurements(self.f)
|
||||||
print pronsole.totalelength(self.f), _("mm of filament used in this print\n")
|
print pronsole.totalelength(self.f), _("mm of filament used in this print\n")
|
||||||
print _("the print goes from %f mm to %f mm in X\nand is %f mm wide\n") % (Xmin, Xmax, Xtot)
|
print _("the print goes from %f mm to %f mm in X\nand is %f mm wide\n") % (Xmin, Xmax, Xtot)
|
||||||
if self.webInterface:
|
|
||||||
self.webInterface.AddLog(_("the print goes from %f mm to %f mm in X\nand is %f mm wide\n") % (Xmin, Xmax, Xtot))
|
|
||||||
print _("the print goes from %f mm to %f mm in Y\nand is %f mm wide\n") % (Ymin, Ymax, Ytot)
|
print _("the print goes from %f mm to %f mm in Y\nand is %f mm wide\n") % (Ymin, Ymax, Ytot)
|
||||||
print _("the print goes from %f mm to %f mm in Z\nand is %f mm high\n") % (Zmin, Zmax, Ztot)
|
print _("the print goes from %f mm to %f mm in Z\nand is %f mm high\n") % (Zmin, Zmax, Ztot)
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
import tornado.ioloop
|
||||||
|
import tornado.web
|
||||||
|
import tornado.websocket
|
||||||
|
import base64
|
||||||
|
import logging
|
||||||
|
import logging.config
|
||||||
|
import tornado.httpserver
|
||||||
|
import tornado.ioloop
|
||||||
|
import tornado.web
|
||||||
|
|
||||||
|
log = logging.getLogger("root")
|
||||||
|
|
||||||
|
def authenticate(realm, authenticator,user_extractor) :
|
||||||
|
"""
|
||||||
|
This is a basic authentication interceptor which
|
||||||
|
protects the desired URIs and requires
|
||||||
|
authentication as per configuration
|
||||||
|
"""
|
||||||
|
def wrapper(self, transforms, *args, **kwargs):
|
||||||
|
def _request_basic_auth(self):
|
||||||
|
if self._headers_written:
|
||||||
|
raise Exception('headers have already been written')
|
||||||
|
|
||||||
|
# If this is a websocket accept parameter-based (user/password) auth:
|
||||||
|
if hasattr(self, 'stream'):
|
||||||
|
"""
|
||||||
|
self.stream.write(tornado.escape.utf8(
|
||||||
|
"HTTP/1.1 401 Unauthorized\r\n"+
|
||||||
|
"Date: Wed, 10 Apr 2013 02:09:52 GMT\r\n"+
|
||||||
|
"Content-Length: 0\r\n"+
|
||||||
|
"Content-Type: text/html; charset=UTF-8\r\n"+
|
||||||
|
"Www-Authenticate: Basic realm=\"auth_realm\"\r\n"+
|
||||||
|
"Server: TornadoServer/3.0.1\r\n\r\n"
|
||||||
|
))
|
||||||
|
self.stream.close()
|
||||||
|
"""
|
||||||
|
# If this is a restful request use the standard tornado methods:
|
||||||
|
else:
|
||||||
|
self.set_status(401)
|
||||||
|
self.set_header('WWW-Authenticate','Basic realm="%s"' % realm)
|
||||||
|
self._transforms = []
|
||||||
|
self.finish()
|
||||||
|
|
||||||
|
return False
|
||||||
|
request = self.request
|
||||||
|
format = ''
|
||||||
|
clazz = self.__class__
|
||||||
|
log.debug('intercepting for class : %s', clazz)
|
||||||
|
try:
|
||||||
|
auth_hdr = request.headers.get('Authorization')
|
||||||
|
|
||||||
|
if auth_hdr == None:
|
||||||
|
return _request_basic_auth(self)
|
||||||
|
if not auth_hdr.startswith('Basic '):
|
||||||
|
return _request_basic_auth(self)
|
||||||
|
|
||||||
|
auth_decoded = base64.decodestring(auth_hdr[6:])
|
||||||
|
username, password = auth_decoded.split(':', 2)
|
||||||
|
|
||||||
|
user_info = authenticator(realm, unicode(username), password)
|
||||||
|
if user_info :
|
||||||
|
self._user_info = user_info
|
||||||
|
self._current_user = user_extractor(user_info)
|
||||||
|
log.debug('authenticated user is : %s',
|
||||||
|
str(self._user_info))
|
||||||
|
else:
|
||||||
|
return _request_basic_auth(self)
|
||||||
|
except Exception, e:
|
||||||
|
return _request_basic_auth(self)
|
||||||
|
return True
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
def interceptor(func):
|
||||||
|
"""
|
||||||
|
This is a class decorator which is helpful in configuring
|
||||||
|
one or more interceptors which are able to intercept, inspect,
|
||||||
|
process and approve or reject further processing of the request
|
||||||
|
"""
|
||||||
|
def classwrapper(cls):
|
||||||
|
def wrapper(old):
|
||||||
|
def inner(self, transforms, *args, **kwargs):
|
||||||
|
log.debug('Invoking wrapper %s',func)
|
||||||
|
ret = func(self,transforms,*args,**kwargs)
|
||||||
|
if ret :
|
||||||
|
return old(self,transforms,*args,**kwargs)
|
||||||
|
else :
|
||||||
|
return ret
|
||||||
|
return inner
|
||||||
|
cls._execute = wrapper(cls._execute)
|
||||||
|
return cls
|
||||||
|
return classwrapper
|
||||||
|
|
||||||
|
print "moo"
|
Binary file not shown.
|
@ -0,0 +1,34 @@
|
||||||
|
html, body
|
||||||
|
{
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body
|
||||||
|
{
|
||||||
|
background: url("/static/img/background.jpg");
|
||||||
|
background-color: black;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: 50% 50%;
|
||||||
|
background-size: auto 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lead-box
|
||||||
|
{
|
||||||
|
position: absolute;
|
||||||
|
text-align: right;
|
||||||
|
top: 80%;
|
||||||
|
margin-top: -40px;
|
||||||
|
padding: 0px;
|
||||||
|
color: white;
|
||||||
|
padding-left: 100px;
|
||||||
|
padding-right: 20px;
|
||||||
|
background: rgba(0, 0, 0, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.lead-box a, .lead-box a:hover
|
||||||
|
{
|
||||||
|
color: #3198EC;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
.sensors
|
||||||
|
{
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sensors>*
|
||||||
|
{
|
||||||
|
margin-left: 40px;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 120%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sensors .val
|
||||||
|
{
|
||||||
|
display: inline-block;
|
||||||
|
width: 50px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sensors .val, .sensors .deg
|
||||||
|
{
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.console
|
||||||
|
{
|
||||||
|
height: 200px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
.console pre
|
||||||
|
{
|
||||||
|
border: 0px;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#temperature-graph
|
||||||
|
{
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#print-job-panel
|
||||||
|
{
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.job-pogress
|
||||||
|
{
|
||||||
|
margin: 80px 0;
|
||||||
|
font-size: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 444 KiB |
|
@ -0,0 +1,145 @@
|
||||||
|
(function() {
|
||||||
|
var $console;
|
||||||
|
|
||||||
|
var windowFocus = true;
|
||||||
|
|
||||||
|
$(window).focus(function() {
|
||||||
|
windowFocus = true;
|
||||||
|
//if ($console) $console.append("Window refocused, restarting graph.\n");
|
||||||
|
$(".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")
|
||||||
|
.stop(true,true)
|
||||||
|
.show()
|
||||||
|
.addClass("in")
|
||||||
|
.removeClass("out");
|
||||||
|
}.debounce());
|
||||||
|
|
||||||
|
var connect = function() {
|
||||||
|
// Let us open a web socket
|
||||||
|
var url = "ws://localhost:8888/socket?user=admin&password=admin";
|
||||||
|
console.log(url);
|
||||||
|
var ws = new WebSocket(url);
|
||||||
|
$(function () {
|
||||||
|
$consoleWrapper = $(".console");
|
||||||
|
$console = $(".console pre");
|
||||||
|
$console.html("Connecting...\n")
|
||||||
|
onConnect(ws)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var updateSensorsUi = function() {
|
||||||
|
$(".sensors .val").each(function() {
|
||||||
|
$(this).html($(this).data("val")||"xx.x");
|
||||||
|
})
|
||||||
|
}.throttle(800);
|
||||||
|
|
||||||
|
var graph = null;
|
||||||
|
var graphData = [];
|
||||||
|
var graphResolution = 40;
|
||||||
|
|
||||||
|
var updateGraphData = function(current) {
|
||||||
|
current.time = Date.now();
|
||||||
|
if(graphData.length == graphResolution) graphData.shift();
|
||||||
|
graphData.push(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
var updateGraphUi = function(current) {
|
||||||
|
if(graph == null)
|
||||||
|
{
|
||||||
|
graph = new Morris.Line({
|
||||||
|
// ID of the element in which to draw the chart.
|
||||||
|
element: "temperature-graph",
|
||||||
|
// Chart data records -- each entry in this array corresponds to a point on
|
||||||
|
// the chart.
|
||||||
|
data: graphData,
|
||||||
|
// The name of the data record attribute that contains x-values.
|
||||||
|
xkey: 'timestamp',
|
||||||
|
// A list of names of data record attributes that contain y-values.
|
||||||
|
ykeys: ['extruder', 'bed'],
|
||||||
|
// Labels for the ykeys -- will be displayed when you hover over the
|
||||||
|
// chart.
|
||||||
|
labels: ['extruder °C', 'bed °C'],
|
||||||
|
hideHover: 'always',
|
||||||
|
ymax: 'auto 250',
|
||||||
|
//pointSize: 0,
|
||||||
|
//parseTime: false,
|
||||||
|
xLabels: "decade"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
graph.setData(graphData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var updateUi = function(msg) {
|
||||||
|
if(windowFocus == false) return;
|
||||||
|
updateSensorsUi();
|
||||||
|
updateGraphUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
var onConnect = function(ws) {
|
||||||
|
ws.onopen = function()
|
||||||
|
{
|
||||||
|
$console.append("Connected.\n");
|
||||||
|
// Web Socket is connected, send data using send()
|
||||||
|
|
||||||
|
};
|
||||||
|
var nextGraphPoint = {};
|
||||||
|
ws.onmessage = function (evt)
|
||||||
|
{
|
||||||
|
msg = JSON.parse(evt.data)
|
||||||
|
if(msg.sensor_changed != undefined)
|
||||||
|
{
|
||||||
|
var sensorNames = ["bed", "extruder"];
|
||||||
|
for (var i = 0; i < sensorNames.length; i++)
|
||||||
|
{
|
||||||
|
var name = msg.sensor_changed.name;
|
||||||
|
var val = parseFloat(msg.sensor_changed.value);
|
||||||
|
nextGraphPoint[name] = val;
|
||||||
|
$("."+name+" .val").data("val", val.format(1))
|
||||||
|
}
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
// websocket is closed.
|
||||||
|
$console.append("\nConnection closed.");
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
if ("WebSocket" in window)
|
||||||
|
{
|
||||||
|
connect();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The browser doesn't support WebSocket
|
||||||
|
alert("Error: WebSocket NOT supported by your Browser!");
|
||||||
|
}
|
||||||
|
})();
|
|
@ -0,0 +1,24 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Pronserve</title>
|
||||||
|
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet">
|
||||||
|
<link href="/static/css/index.css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="lead-box">
|
||||||
|
<h1>
|
||||||
|
Your printer just got a whole lot better.
|
||||||
|
</h1>
|
||||||
|
<p class="lead">
|
||||||
|
Pronserve is ready to print. Why not try it out with
|
||||||
|
<a href="/inspect">Inspector</a> or
|
||||||
|
<a href="https://github.com/D1plo1d/ctrlpanel">Ctrl Panel</a>?
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -0,0 +1,57 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Pronserve Inspector</title>
|
||||||
|
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="http://cdn.oesmith.co.uk/morris-0.4.1.min.css">
|
||||||
|
<link href="/static/css/inspect.css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row-fluid">
|
||||||
|
<div class="span12">
|
||||||
|
<h1>
|
||||||
|
Pronserve Inspector
|
||||||
|
</h1>
|
||||||
|
<h2>Console</h2>
|
||||||
|
<div class="well console">
|
||||||
|
<pre>
|
||||||
|
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">°C</span>
|
||||||
|
</div>
|
||||||
|
<div class="bed pull-right">
|
||||||
|
Bed: <span class="val"/>xx.x</span><span class="deg">°C</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h2>Temperature</h2>
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
<div id="temperature-graph">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</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>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/sugar/1.3.9/sugar.min.js"></script>
|
||||||
|
<script src="//cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
|
||||||
|
<script src="http://cdn.oesmith.co.uk/morris-0.4.1.min.js"></script>
|
||||||
|
<script src="/static/js/inspect.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -1,206 +0,0 @@
|
||||||
#title
|
|
||||||
{
|
|
||||||
text-align:center;
|
|
||||||
color:red;
|
|
||||||
}
|
|
||||||
|
|
||||||
#mainmenu
|
|
||||||
{
|
|
||||||
margin: 0;
|
|
||||||
padding: 0 0 20px 10px;
|
|
||||||
border-bottom: 1px solid #000;
|
|
||||||
}
|
|
||||||
#mainmenu ul, #mainmenu li
|
|
||||||
{
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
display: inline;
|
|
||||||
list-style-type: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#mainmenu a:link, #mainmenu a:visited
|
|
||||||
{
|
|
||||||
float: left;
|
|
||||||
line-height: 14px;
|
|
||||||
font-weight: bold;
|
|
||||||
margin: 0 10px 4px 10px;
|
|
||||||
text-decoration: none;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
#mainmenu a:link#current, #mainmenu a:visited#current, #mainmenu a:hover
|
|
||||||
{
|
|
||||||
border-bottom: 4px solid #000;
|
|
||||||
padding-bottom: 2px;
|
|
||||||
background: transparent;
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
#mainmenu a:hover { color: #000; }
|
|
||||||
|
|
||||||
#content{
|
|
||||||
padding-top: 25px;
|
|
||||||
}
|
|
||||||
#controls{
|
|
||||||
float:left;
|
|
||||||
padding:0 0 1em 0;
|
|
||||||
overflow:hidden;
|
|
||||||
width:71%; /* right column content width */
|
|
||||||
left:102%; /* 100% plus left column left padding */
|
|
||||||
}
|
|
||||||
#control_xy{
|
|
||||||
display:inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
#control_z{
|
|
||||||
display:inline;
|
|
||||||
position:absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
#gui{
|
|
||||||
float:left;
|
|
||||||
padding:0 0 1em 0;
|
|
||||||
overflow:hidden;
|
|
||||||
width:21%; /* left column content width (column width minus left and right padding) */
|
|
||||||
left:6%; /* (right column left and right padding) plus (left column left padding) */
|
|
||||||
|
|
||||||
}
|
|
||||||
#controls
|
|
||||||
{
|
|
||||||
width:21%; /* Width of left column content (column width minus padding on either side) */
|
|
||||||
left:31%; /* width of (right column) plus (center column left and right padding) plus (left column left padding) */
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#controls ul
|
|
||||||
{
|
|
||||||
list-style: none;
|
|
||||||
margin: 0px;
|
|
||||||
padding: 0px;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#controls ul li
|
|
||||||
{
|
|
||||||
margin: 0px;
|
|
||||||
padding: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#controls ul li a
|
|
||||||
{
|
|
||||||
font-size: 80%;
|
|
||||||
display: block;
|
|
||||||
border-bottom: 1px dashed #C39C4E;
|
|
||||||
padding: 5px 0px 2px 4px;
|
|
||||||
text-decoration: none;
|
|
||||||
color: #666666;
|
|
||||||
width:160px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#controls ul li a:hover, #controls ul li a:focus
|
|
||||||
{
|
|
||||||
color: #000000;
|
|
||||||
background-color: #eeeeee;
|
|
||||||
}
|
|
||||||
|
|
||||||
#settings
|
|
||||||
{
|
|
||||||
margin: 0px;
|
|
||||||
padding-top: 50px;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#settings table
|
|
||||||
{
|
|
||||||
font-family: verdana,arial,sans-serif;
|
|
||||||
font-size:11px;
|
|
||||||
color:#333333;
|
|
||||||
border-width: 1px;
|
|
||||||
border-color: #999999;
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
#settings table th {
|
|
||||||
background-color:#c3dde0;
|
|
||||||
border-width: 1px;
|
|
||||||
padding: 8px;
|
|
||||||
border-style: solid;
|
|
||||||
border-color: #a9c6c9;
|
|
||||||
}
|
|
||||||
#settings table tr {
|
|
||||||
background-color:#d4e3e5;
|
|
||||||
}
|
|
||||||
#settings table td {
|
|
||||||
border-width: 1px;
|
|
||||||
padding: 8px;
|
|
||||||
border-style: solid;
|
|
||||||
border-color: #a9c6c9;
|
|
||||||
}
|
|
||||||
|
|
||||||
#status{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#console{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#file{
|
|
||||||
position:relative;
|
|
||||||
float:left;
|
|
||||||
width:100%;
|
|
||||||
height:20px; /* Height of the footer */
|
|
||||||
background:#eee;
|
|
||||||
}
|
|
||||||
|
|
||||||
#logframe{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#temp{
|
|
||||||
}
|
|
||||||
#tempmenu
|
|
||||||
{
|
|
||||||
padding: 0 0 10px 10px;
|
|
||||||
position: relative;
|
|
||||||
float: left;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
#tempmenu ul, #tempmenu li
|
|
||||||
{
|
|
||||||
margin: 0;
|
|
||||||
display: inline;
|
|
||||||
list-style-type: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#tempmenu b
|
|
||||||
{
|
|
||||||
padding-top: 4px;
|
|
||||||
float: left;
|
|
||||||
line-height: 14px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #888;
|
|
||||||
margin: 0 10px 4px 10px;
|
|
||||||
text-decoration: none;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
#tempmenu a:link, #tempmenu a:visited
|
|
||||||
{
|
|
||||||
float: left;
|
|
||||||
border-bottom: 1px solid #000;
|
|
||||||
line-height: 14px;
|
|
||||||
font-weight: bold;
|
|
||||||
margin: 0 10px 4px 10px;
|
|
||||||
text-decoration: none;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
#tempmenu a:link#tempmenu, #tempmenu a:visited#current, #tempmenu a:hover
|
|
||||||
{
|
|
||||||
border-bottom: 2px solid #000;
|
|
||||||
padding-bottom: 2px;
|
|
||||||
background: transparent;
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
#tempmenu a:hover { color: #000; }
|
|
|
@ -1,79 +0,0 @@
|
||||||
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;
|
|
||||||
}
|
|
Loading…
Reference in New Issue