commit
8c24401ddb
|
@ -2,3 +2,4 @@
|
|||
.pronsolerc
|
||||
*.swp
|
||||
*.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
|
||||
* 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
|
||||
* webinterface.py is a browser-usable remote control function for Pronterface
|
||||
|
||||
# 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.
|
||||
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.
|
||||
The www server will start on the port/address you have chosen.
|
||||
# USING PRONSERVE
|
||||
|
||||
## 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
|
||||
command prompt in its directory and running python setup.py install.
|
||||
* python (ideally 2.6.x or 2.7.x),
|
||||
* 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
|
||||
* 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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
# 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:
|
||||
# get device caps from firmware: max speed, acceleration/axis (including extruder)
|
||||
# calculate the maximum move duration accounting for above ;)
|
||||
# print ".... estimating ...."
|
||||
# self.log(".... estimating ....")
|
||||
for i in g:
|
||||
i = i.split(";")[0]
|
||||
if "G4" in i or "G1" in i:
|
||||
|
@ -119,7 +119,7 @@ def estimate_duration(g):
|
|||
|
||||
if z > lastz:
|
||||
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
|
||||
|
||||
lastx = x
|
||||
|
@ -128,7 +128,7 @@ def estimate_duration(g):
|
|||
laste = e
|
||||
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)))
|
||||
|
||||
def confirm():
|
||||
|
@ -252,6 +252,7 @@ class pronsole(cmd.Cmd):
|
|||
self.settings._bedtemp_abs_cb = self.set_temp_preset
|
||||
self.settings._bedtemp_pla_cb = self.set_temp_preset
|
||||
self.monitoring = 0
|
||||
self.silent = False
|
||||
self.helpdict = {}
|
||||
self.helpdict["baudrate"] = _("Communications Speed (default: 115200)")
|
||||
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 ",
|
||||
"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):
|
||||
"""A function to generate prompts so that we can do dynamic prompts. """
|
||||
if self.in_macro:
|
||||
|
@ -323,11 +327,11 @@ class pronsole(cmd.Cmd):
|
|||
if not key.startswith("bed"):
|
||||
self.temps["pla"] = str(self.settings.temperature_pla)
|
||||
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:
|
||||
self.bedtemps["pla"] = str(self.settings.bedtemp_pla)
|
||||
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):
|
||||
"""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*")
|
||||
|
||||
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.flush()
|
||||
|
||||
|
@ -356,7 +363,7 @@ class pronsole(cmd.Cmd):
|
|||
self.help_gcodes()
|
||||
|
||||
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):
|
||||
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__, "help_"+self.cur_macro_name, lambda self, macro_name = self.cur_macro_name: self.subhelp_macro(macro_name))
|
||||
if not self.processing_rc:
|
||||
print "Macro '"+self.cur_macro_name+"' defined"
|
||||
self.log("Macro '"+self.cur_macro_name+"' defined")
|
||||
# save it
|
||||
if not self.processing_args:
|
||||
macro_key = "macro "+self.cur_macro_name
|
||||
|
@ -398,7 +405,7 @@ class pronsole(cmd.Cmd):
|
|||
macro_def += self.cur_macro_def
|
||||
self.save_in_rc(macro_key, macro_def)
|
||||
else:
|
||||
print "Empty macro - cancelled"
|
||||
self.log("Empty macro - cancelled")
|
||||
del self.cur_macro_name, self.cur_macro_def
|
||||
|
||||
def compile_macro_line(self, line):
|
||||
|
@ -413,7 +420,7 @@ class pronsole(cmd.Cmd):
|
|||
|
||||
def compile_macro(self, macro_name, macro_def):
|
||||
if macro_def.strip() == "":
|
||||
print "Empty macro - cancelled"
|
||||
self.log("Empty macro - cancelled")
|
||||
return
|
||||
pycode = "def macro(self,*arg):\n"
|
||||
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):
|
||||
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_def = ""
|
||||
self.onecmd = self.hook_macro # override onecmd temporarily
|
||||
|
@ -438,11 +445,11 @@ class pronsole(cmd.Cmd):
|
|||
if macro_name in self.macros.keys():
|
||||
delattr(self.__class__, "do_"+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:
|
||||
self.save_in_rc("macro "+macro_name, "")
|
||||
else:
|
||||
print "Macro '"+macro_name+"' is not defined"
|
||||
self.log("Macro '"+macro_name+"' is not defined")
|
||||
def do_macro(self, args):
|
||||
if args.strip()=="":
|
||||
self.print_topics("User-defined macros", self.macros.keys(), 15, 80)
|
||||
|
@ -450,7 +457,7 @@ class pronsole(cmd.Cmd):
|
|||
arglist = args.split(None, 1)
|
||||
macro_name = arglist[0]
|
||||
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
|
||||
if len(arglist) == 2:
|
||||
macro_def = arglist[1]
|
||||
|
@ -470,24 +477,24 @@ class pronsole(cmd.Cmd):
|
|||
self.start_macro(macro_name)
|
||||
|
||||
def help_macro(self):
|
||||
print "Define single-line macro: macro <name> <definition>"
|
||||
print "Define multi-line macro: macro <name>"
|
||||
print "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"
|
||||
print "Delete macro: macro <name> /d"
|
||||
print "Show macro definition: macro <name> /s"
|
||||
print "'macro' without arguments displays list of defined macros"
|
||||
self.log("Define single-line macro: macro <name> <definition>")
|
||||
self.log("Define multi-line macro: macro <name>")
|
||||
self.log("Enter macro definition in indented lines. Use {0} .. {N} to substitute macro arguments")
|
||||
self.log("Enter python code, prefixed with ! Use arg[0] .. arg[N] to substitute macro arguments")
|
||||
self.log("Delete macro: macro <name> /d")
|
||||
self.log("Show macro definition: macro <name> /s")
|
||||
self.log("'macro' without arguments displays list of defined macros")
|
||||
|
||||
def subhelp_macro(self, macro_name):
|
||||
if macro_name in self.macros.keys():
|
||||
macro_def = self.macros[macro_name]
|
||||
if "\n" in macro_def:
|
||||
print "Macro '"+macro_name+"' defined as:"
|
||||
print self.macros[macro_name]+"----------------"
|
||||
self.log("Macro '"+macro_name+"' defined as:")
|
||||
self.log(self.macros[macro_name]+"----------------")
|
||||
else:
|
||||
print "Macro '"+macro_name+"' defined as: '"+macro_def+"'"
|
||||
self.log("Macro '"+macro_name+"' defined as: '"+macro_def+"'")
|
||||
else:
|
||||
print "Macro '"+macro_name+"' is not defined"
|
||||
self.log("Macro '"+macro_name+"' is not defined")
|
||||
|
||||
def set(self, var, str):
|
||||
try:
|
||||
|
@ -496,29 +503,29 @@ class pronsole(cmd.Cmd):
|
|||
if not self.processing_rc and not self.processing_args:
|
||||
self.save_in_rc("set "+var, "set %s %s" % (var, value))
|
||||
except AttributeError:
|
||||
print "Unknown variable '%s'" % var
|
||||
self.log("Unknown variable '%s'" % var)
|
||||
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):
|
||||
args = argl.split(None, 1)
|
||||
if len(args) < 1:
|
||||
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
|
||||
value = getattr(self.settings, args[0])
|
||||
if len(args) < 2:
|
||||
try:
|
||||
print "%s = %s" % (args[0], getattr(self.settings, args[0]))
|
||||
self.log("%s = %s" % (args[0], getattr(self.settings, args[0])))
|
||||
except AttributeError:
|
||||
print "Unknown variable '%s'" % args[0]
|
||||
self.log("Unknown variable '%s'" % args[0])
|
||||
return
|
||||
self.set(args[0], args[1])
|
||||
|
||||
def help_set(self):
|
||||
print "Set variable: set <variable> <value>"
|
||||
print "Show variable: set <variable>"
|
||||
print "'set' without arguments displays all variables"
|
||||
self.log("Set variable: set <variable> <value>")
|
||||
self.log("Show variable: set <variable>")
|
||||
self.log("'set' without arguments displays all variables")
|
||||
|
||||
def complete_set(self, text, line, begidx, endidx):
|
||||
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()
|
||||
rco.close()
|
||||
#if definition != "":
|
||||
# print "Saved '"+key+"' to '"+self.rc_filename+"'"
|
||||
# self.log("Saved '"+key+"' to '"+self.rc_filename+"'")
|
||||
#else:
|
||||
# print "Removed '"+key+"' from '"+self.rc_filename+"'"
|
||||
# self.log("Removed '"+key+"' from '"+self.rc_filename+"'")
|
||||
except Exception, e:
|
||||
print "Saving failed for", key+":", str(e)
|
||||
self.log("Saving failed for", key+":", str(e))
|
||||
finally:
|
||||
del rci, rco
|
||||
|
||||
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()
|
||||
cmd.Cmd.preloop(self)
|
||||
|
||||
|
@ -626,12 +633,12 @@ class pronsole(cmd.Cmd):
|
|||
try:
|
||||
baud = int(a[1])
|
||||
except:
|
||||
print "Bad baud value '"+a[1]+"' ignored"
|
||||
self.log("Bad baud value '"+a[1]+"' ignored")
|
||||
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
|
||||
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:
|
||||
self.settings.port = port
|
||||
self.save_in_rc("set port", "set port %s" % port)
|
||||
|
@ -641,14 +648,14 @@ class pronsole(cmd.Cmd):
|
|||
self.p.connect(port, baud)
|
||||
|
||||
def help_connect(self):
|
||||
print "Connect to printer"
|
||||
print "connect <port> <baudrate>"
|
||||
print "If port and baudrate are not specified, connects to first detected port at 115200bps"
|
||||
self.log("Connect to printer")
|
||||
self.log("connect <port> <baudrate>")
|
||||
self.log("If port and baudrate are not specified, connects to first detected port at 115200bps")
|
||||
ports = self.scanserial()
|
||||
if(len(ports)):
|
||||
print "Available ports: ", " ".join(ports)
|
||||
self.log("Available ports: ", " ".join(ports))
|
||||
else:
|
||||
print "No serial ports were automatically found."
|
||||
self.log("No serial ports were automatically found.")
|
||||
|
||||
def complete_connect(self, text, line, begidx, endidx):
|
||||
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()
|
||||
|
||||
def help_disconnect(self):
|
||||
print "Disconnects from the printer"
|
||||
self.log("Disconnects from the printer")
|
||||
|
||||
def do_load(self,l):
|
||||
self._do_load(l)
|
||||
|
||||
def _do_load(self,l):
|
||||
if len(l)==0:
|
||||
print "No file name given."
|
||||
self.log("No file name given.")
|
||||
return
|
||||
print "Loading file:"+l
|
||||
self.log("Loading file:"+l)
|
||||
if not(os.path.exists(l)):
|
||||
print "File not found!"
|
||||
self.log("File not found!")
|
||||
return
|
||||
self.f = [i.replace("\n", "").replace("\r", "") for i in open(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):
|
||||
s = line.split()
|
||||
|
@ -690,32 +697,32 @@ class pronsole(cmd.Cmd):
|
|||
return glob.glob("*/")+glob.glob("*.g*")
|
||||
|
||||
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):
|
||||
if len(l) == 0:
|
||||
print "No file name given."
|
||||
self.log("No file name given.")
|
||||
return
|
||||
print "Loading file:"+l.split()[0]
|
||||
self.log("Loading file:"+l.split()[0])
|
||||
if not(os.path.exists(l.split()[0])):
|
||||
print "File not found!"
|
||||
self.log("File not found!")
|
||||
return
|
||||
if not self.p.online:
|
||||
print "Not connected to printer."
|
||||
self.log("Not connected to printer.")
|
||||
return
|
||||
self.f = [i.replace("\n", "") for i in open(l.split()[0])]
|
||||
self.filename = l.split()[0]
|
||||
print "Loaded ", l, ", ", len(self.f)," lines."
|
||||
self.log("Loaded ", l, ", ", len(self.f)," lines.")
|
||||
tname = ""
|
||||
if len(l.split())>1:
|
||||
tname = l.split()[1]
|
||||
else:
|
||||
print "please enter target name in 8.3 format."
|
||||
self.log("please enter target name in 8.3 format.")
|
||||
return
|
||||
print "Uploading as ", tname
|
||||
print("Uploading "+self.filename)
|
||||
self.log("Uploading as ", tname)
|
||||
self.log(("Uploading "+self.filename))
|
||||
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)
|
||||
try:
|
||||
sys.stdout.write("Progress: 00.0%")
|
||||
|
@ -733,16 +740,16 @@ class pronsole(cmd.Cmd):
|
|||
self.recvlisteners+=[self.listfiles]
|
||||
self.p.send_now("M20")
|
||||
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
|
||||
except:
|
||||
print "...interrupted!"
|
||||
self.log("...interrupted!")
|
||||
self.p.pause()
|
||||
self.p.send_now("M29 "+tname)
|
||||
time.sleep(0.2)
|
||||
self.p.clear = 1
|
||||
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):
|
||||
|
@ -756,23 +763,23 @@ class pronsole(cmd.Cmd):
|
|||
return glob.glob("*/")+glob.glob("*.g*")
|
||||
|
||||
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):
|
||||
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:
|
||||
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):
|
||||
if self.f is None:
|
||||
print "No file loaded. Please use load first."
|
||||
self.log("No file loaded. Please use load first.")
|
||||
return
|
||||
if not self.p.online:
|
||||
print "Not connected to printer."
|
||||
self.log("Not connected to printer.")
|
||||
return
|
||||
print("Printing "+self.filename)
|
||||
print("You can monitor the print with the monitor command.")
|
||||
self.log(("printing "+self.filename))
|
||||
self.log(("You can monitor the print with the monitor command."))
|
||||
self.p.startprint(self.f)
|
||||
#self.p.pause()
|
||||
#self.paused = True
|
||||
|
@ -783,7 +790,7 @@ class pronsole(cmd.Cmd):
|
|||
self.p.send_now("M25")
|
||||
else:
|
||||
if(not self.p.printing):
|
||||
print "Not printing, cannot pause."
|
||||
self.log("Not self.log(ing, cannot pause.")
|
||||
return
|
||||
self.p.pause()
|
||||
#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)
|
||||
|
||||
def help_pause(self):
|
||||
print "Pauses a running print"
|
||||
self.log("Pauses a running print")
|
||||
|
||||
def do_resume(self, l):
|
||||
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
|
||||
self.paused = False
|
||||
if self.sdprinting:
|
||||
|
@ -806,7 +813,7 @@ class pronsole(cmd.Cmd):
|
|||
self.p.resume()
|
||||
|
||||
def help_resume(self):
|
||||
print "Resumes a paused print."
|
||||
self.log("Resumes a paused print.")
|
||||
|
||||
def emptyline(self):
|
||||
pass
|
||||
|
@ -825,33 +832,33 @@ class pronsole(cmd.Cmd):
|
|||
|
||||
def do_ls(self, l):
|
||||
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
|
||||
self.listing = 2
|
||||
self.sdfiles = []
|
||||
self.recvlisteners+=[self.listfiles]
|
||||
self.p.send_now("M20")
|
||||
time.sleep(0.5)
|
||||
print " ".join(self.sdfiles)
|
||||
self.log(" ".join(self.sdfiles))
|
||||
|
||||
def help_ls(self):
|
||||
print "lists files on the SD card"
|
||||
self.log("lists files on the SD card")
|
||||
|
||||
def waitforsdresponse(self, l):
|
||||
if "file.open failed" in l:
|
||||
print "Opening file failed."
|
||||
self.log("Opening file failed.")
|
||||
self.recvlisteners.remove(self.waitforsdresponse)
|
||||
return
|
||||
if "File opened" in l:
|
||||
print l
|
||||
self.log(l)
|
||||
if "File selected" in l:
|
||||
print "Starting print"
|
||||
self.log("Starting print")
|
||||
self.p.send_now("M24")
|
||||
self.sdprinting = 1
|
||||
#self.recvlisteners.remove(self.waitforsdresponse)
|
||||
return
|
||||
if "Done printing file" in l:
|
||||
print l
|
||||
self.log(l)
|
||||
self.sdprinting = 0
|
||||
self.recvlisteners.remove(self.waitforsdresponse)
|
||||
return
|
||||
|
@ -868,11 +875,11 @@ class pronsole(cmd.Cmd):
|
|||
self.p.reset()
|
||||
|
||||
def help_reset(self):
|
||||
print "Resets the printer."
|
||||
self.log("Resets the printer.")
|
||||
|
||||
def do_sdprint(self, l):
|
||||
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
|
||||
self.listing = 2
|
||||
self.sdfiles = []
|
||||
|
@ -880,17 +887,17 @@ class pronsole(cmd.Cmd):
|
|||
self.p.send_now("M20")
|
||||
time.sleep(0.5)
|
||||
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
|
||||
self.recvlisteners+=[self.waitforsdresponse]
|
||||
self.p.send_now("M23 "+l.lower())
|
||||
print "Printing file: "+l.lower()+" from SD card."
|
||||
print "Requesting SD print..."
|
||||
self.log("printing file: "+l.lower()+" from SD card.")
|
||||
self.log("Requesting SD print...")
|
||||
time.sleep(1)
|
||||
|
||||
def help_sdprint(self):
|
||||
print "Print a file from the SD card. Tabcompletes with available file names."
|
||||
print "sdprint filename.g"
|
||||
self.log("print a file from the SD card. Tabcompletes with available file names.")
|
||||
self.log("sdprint filename.g")
|
||||
|
||||
def complete_sdprint(self, text, line, begidx, endidx):
|
||||
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[:5] == "echo:":
|
||||
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.flush()
|
||||
for i in self.recvlisteners:
|
||||
i(l)
|
||||
|
||||
def help_shell(self):
|
||||
print "Executes a python command. Example:"
|
||||
print "! os.listdir('.')"
|
||||
self.log("Executes a python command. Example:")
|
||||
self.log("! os.listdir('.')")
|
||||
|
||||
def default(self, l):
|
||||
if(l[0] in self.commandprefixes.upper()):
|
||||
if(self.p and self.p.online):
|
||||
if(not self.p.loud):
|
||||
print "SENDING:"+l
|
||||
self.log("SENDING:"+l)
|
||||
self.p.send_now(l)
|
||||
else:
|
||||
print "Printer is not online."
|
||||
self.log("printer is not online.")
|
||||
return
|
||||
elif(l[0] in self.commandprefixes.lower()):
|
||||
if(self.p and self.p.online):
|
||||
if(not self.p.loud):
|
||||
print "SENDING:"+l.upper()
|
||||
self.log("SENDING:"+l.upper())
|
||||
self.p.send_now(l.upper())
|
||||
else:
|
||||
print "Printer is not online."
|
||||
self.log("printer is not online.")
|
||||
return
|
||||
else:
|
||||
cmd.Cmd.default(self, l)
|
||||
|
@ -942,6 +949,10 @@ class pronsole(cmd.Cmd):
|
|||
def help_help(self):
|
||||
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):
|
||||
if "dynamic" in l:
|
||||
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)
|
||||
|
||||
def help_gettemp(self):
|
||||
print "Read the extruder and bed temperature."
|
||||
self.log("Read the extruder and bed temperature.")
|
||||
|
||||
def do_settemp(self, l):
|
||||
try:
|
||||
|
@ -970,18 +981,18 @@ class pronsole(cmd.Cmd):
|
|||
return
|
||||
if self.p.online:
|
||||
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:
|
||||
print "Printer is not online."
|
||||
self.log("printer is not online.")
|
||||
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:
|
||||
print "You must enter a temperature."
|
||||
self.log("You must enter a temperature.")
|
||||
|
||||
def help_settemp(self):
|
||||
print "Sets the hotend temperature to the value entered."
|
||||
print "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("Sets the hotend temperature to the value entered.")
|
||||
self.log("Enter either a temperature in celsius or one of the following keywords")
|
||||
self.log(", ".join([i+"("+self.temps[i]+")" for i in self.temps.keys()]))
|
||||
|
||||
def complete_settemp(self, text, line, begidx, endidx):
|
||||
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 self.p.online:
|
||||
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:
|
||||
print "Printer is not online."
|
||||
self.log("printer is not online.")
|
||||
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:
|
||||
print "You must enter a temperature."
|
||||
self.log("You must enter a temperature.")
|
||||
|
||||
def help_bedtemp(self):
|
||||
print "Sets the bed temperature to the value entered."
|
||||
print "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("Sets the bed temperature to the value entered.")
|
||||
self.log("Enter either a temperature in celsius or one of the following keywords")
|
||||
self.log(", ".join([i+"("+self.bedtemps[i]+")" for i in self.bedtemps.keys()]))
|
||||
|
||||
def complete_bedtemp(self, text, line, begidx, endidx):
|
||||
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):
|
||||
if(len(l.split())<2):
|
||||
print "No move specified."
|
||||
self.log("No move specified.")
|
||||
return
|
||||
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
|
||||
if not self.p.online:
|
||||
print "Printer is not online. Unable to move."
|
||||
self.log("printer is not online. Unable to move.")
|
||||
return
|
||||
l = l.split()
|
||||
if(l[0].lower()=="x"):
|
||||
|
@ -1037,13 +1048,13 @@ class pronsole(cmd.Cmd):
|
|||
feed = self.settings.e_feedrate
|
||||
axis = "E"
|
||||
else:
|
||||
print "Unknown axis."
|
||||
self.log("Unknown axis.")
|
||||
return
|
||||
dist = 0
|
||||
try:
|
||||
dist = float(l[1])
|
||||
except:
|
||||
print "Invalid distance"
|
||||
self.log("Invalid distance")
|
||||
return
|
||||
try:
|
||||
feed = int(l[2])
|
||||
|
@ -1054,11 +1065,11 @@ class pronsole(cmd.Cmd):
|
|||
self.p.send_now("G90")
|
||||
|
||||
def help_move(self):
|
||||
print "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)"
|
||||
print "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)"
|
||||
print "Common amounts are in the tabcomplete list."
|
||||
self.log("Move an axis. Specify the name of the axis and the amount. ")
|
||||
self.log("move X 10 will move the X axis forward by 10mm at ", self.settings.xy_feedrate, "mm/min (default XY speed)")
|
||||
self.log("move Y 10 5000 will move the Y axis forward by 10mm at 5000mm/min")
|
||||
self.log("move Z -1 will move the Z axis down by 1mm at ", self.settings.z_feedrate, "mm/min (default Z speed)")
|
||||
self.log("Common amounts are in the tabcomplete list.")
|
||||
|
||||
def complete_move(self, text, line, begidx, endidx):
|
||||
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
|
||||
feed = self.settings.e_feedrate#default speed
|
||||
if not self.p.online:
|
||||
print "Printer is not online. Unable to move."
|
||||
self.log("printer is not online. Unable to move.")
|
||||
return
|
||||
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
|
||||
ls = l.split()
|
||||
if len(ls):
|
||||
try:
|
||||
length = float(ls[0])
|
||||
except:
|
||||
print "Invalid length given."
|
||||
self.log("Invalid length given.")
|
||||
if len(ls)>1:
|
||||
try:
|
||||
feed = int(ls[1])
|
||||
except:
|
||||
print "Invalid speed given."
|
||||
self.log("Invalid speed given.")
|
||||
if override is not None:
|
||||
length = override
|
||||
feed = overridefeed
|
||||
if length > 0:
|
||||
print "Extruding %fmm of filament."%(length,)
|
||||
self.log("Extruding %fmm of filament."%(length,))
|
||||
elif length <0:
|
||||
print "Reversing %fmm of filament."%(-1*length,)
|
||||
self.log("Reversing %fmm of filament."%(-1*length,))
|
||||
else:
|
||||
"Length is 0, not doing anything."
|
||||
self.p.send_now("G91")
|
||||
|
@ -1108,40 +1119,40 @@ class pronsole(cmd.Cmd):
|
|||
self.p.send_now("G90")
|
||||
|
||||
def help_extrude(self):
|
||||
print "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)"
|
||||
print "extrude 20 - extrudes 20mm of filament at 300mm/min (5mm/s)"
|
||||
print "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("Extrudes a length of filament, 5mm by default, or the number of mm given as a parameter")
|
||||
self.log("extrude - extrudes 5mm of filament at 300mm/min (5mm/s)")
|
||||
self.log("extrude 20 - extrudes 20mm of filament at 300mm/min (5mm/s)")
|
||||
self.log("extrude -5 - REVERSES 5mm of filament at 300mm/min (5mm/s)")
|
||||
self.log("extrude 10 210 - extrudes 10mm of filament at 210mm/min (3.5mm/s)")
|
||||
|
||||
def do_reverse(self, l):
|
||||
length = 5#default extrusion length
|
||||
feed = self.settings.e_feedrate#default speed
|
||||
if not self.p.online:
|
||||
print "Printer is not online. Unable to move."
|
||||
self.log("printer is not online. Unable to move.")
|
||||
return
|
||||
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
|
||||
ls = l.split()
|
||||
if len(ls):
|
||||
try:
|
||||
length = float(ls[0])
|
||||
except:
|
||||
print "Invalid length given."
|
||||
self.log("Invalid length given.")
|
||||
if len(ls)>1:
|
||||
try:
|
||||
feed = int(ls[1])
|
||||
except:
|
||||
print "Invalid speed given."
|
||||
self.log("Invalid speed given.")
|
||||
self.do_extrude("", length*-1.0, feed)
|
||||
|
||||
def help_reverse(self):
|
||||
print "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)"
|
||||
print "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)"
|
||||
print "reverse -5 - EXTRUDES 5mm of filament at 300mm/min (5mm/s)"
|
||||
self.log("Reverses the extruder, 5mm by default, or the number of mm given as a parameter")
|
||||
self.log("reverse - reverses 5mm of filament at 300mm/min (5mm/s)")
|
||||
self.log("reverse 20 - reverses 20mm of filament at 300mm/min (5mm/s)")
|
||||
self.log("reverse 10 210 - extrudes 10mm of filament at 210mm/min (3.5mm/s)")
|
||||
self.log("reverse -5 - EXTRUDES 5mm of filament at 300mm/min (5mm/s)")
|
||||
|
||||
def do_exit(self, l):
|
||||
if self.status.extruder_temp_target != 0:
|
||||
|
@ -1151,35 +1162,35 @@ class pronsole(cmd.Cmd):
|
|||
if self.status.bed_temp_taret != 0:
|
||||
print "Setting bed temp to 0"
|
||||
self.p.send_now("M140 S0.0")
|
||||
print "Disconnecting from printer..."
|
||||
self.log("Disconnecting from printer...")
|
||||
print self.p.printing
|
||||
if self.p.printing:
|
||||
print "Are you sure you want to exit while printing?"
|
||||
print "(this will terminate the print)."
|
||||
if not confirm():
|
||||
return False
|
||||
print "Exiting program. Goodbye!"
|
||||
self.log("Exiting program. Goodbye!")
|
||||
self.p.disconnect()
|
||||
return True
|
||||
|
||||
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):
|
||||
interval = 5
|
||||
if not self.p.online:
|
||||
print "Printer is not online. Please connect first."
|
||||
self.log("printer is not online. Please connect first.")
|
||||
return
|
||||
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
|
||||
print "Monitoring printer, use ^C to interrupt."
|
||||
self.log("Monitoring printer, use ^C to interrupt.")
|
||||
if len(l):
|
||||
try:
|
||||
interval = float(l)
|
||||
except:
|
||||
print "Invalid period given."
|
||||
print "Updating values every %f seconds."%(interval,)
|
||||
self.log("Invalid period given.")
|
||||
self.log("Updating values every %f seconds."%(interval,))
|
||||
self.monitoring = 1
|
||||
prev_msg_len = 0
|
||||
try:
|
||||
|
@ -1197,17 +1208,18 @@ class pronsole(cmd.Cmd):
|
|||
progress = self.percentdone
|
||||
progress = int(progress*10)/10.0 #limit precision
|
||||
prev_msg = preface + str(progress) + "%"
|
||||
sys.stdout.write("\r" + prev_msg.ljust(prev_msg_len))
|
||||
sys.stdout.flush()
|
||||
if self.silent == False:
|
||||
sys.stdout.write("\r" + prev_msg.ljust(prev_msg_len))
|
||||
sys.stdout.flush()
|
||||
prev_msg_len = len(prev_msg)
|
||||
except KeyboardInterrupt:
|
||||
print "Done monitoring."
|
||||
if self.silent == False: print "Done monitoring."
|
||||
self.monitoring = 0
|
||||
|
||||
def help_monitor(self):
|
||||
print "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"
|
||||
print "monitor 2 - Reports temperature and SD print status (if SD printing) every 2 seconds"
|
||||
self.log("Monitor a machine's temperatures and an SD print's status.")
|
||||
self.log("monitor - Reports temperature and SD print status (if SD printing) every 5 seconds")
|
||||
self.log("monitor 2 - Reports temperature and SD print status (if SD printing) every 2 seconds")
|
||||
|
||||
def expandcommand(self, c):
|
||||
return c.replace("$python", sys.executable)
|
||||
|
@ -1215,31 +1227,31 @@ class pronsole(cmd.Cmd):
|
|||
def do_skein(self, l):
|
||||
l = l.split()
|
||||
if len(l) == 0:
|
||||
print "No file name given."
|
||||
self.log("No file name given.")
|
||||
return
|
||||
settings = 0
|
||||
if(l[0]=="set"):
|
||||
settings = 1
|
||||
else:
|
||||
print "Skeining file:"+l[0]
|
||||
self.log("Skeining file:"+l[0])
|
||||
if not(os.path.exists(l[0])):
|
||||
print "File not found!"
|
||||
self.log("File not found!")
|
||||
return
|
||||
try:
|
||||
import shlex
|
||||
if(settings):
|
||||
param = self.expandcommand(self.settings.sliceoptscommand).replace("\\", "\\\\").encode()
|
||||
print "Entering slicer settings: ", param
|
||||
self.log("Entering slicer settings: ", param)
|
||||
subprocess.call(shlex.split(param))
|
||||
else:
|
||||
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())]
|
||||
subprocess.call(params)
|
||||
print "Loading sliced file."
|
||||
self.log("Loading sliced file.")
|
||||
self.do_load(l[0].replace(".stl", "_export.gcode"))
|
||||
except Exception, e:
|
||||
print "Skeinforge execution failed: ", e
|
||||
self.log("Skeinforge execution failed: ", e)
|
||||
|
||||
def complete_skein(self, text, line, begidx, endidx):
|
||||
s = line.split()
|
||||
|
@ -1252,18 +1264,18 @@ class pronsole(cmd.Cmd):
|
|||
return glob.glob("*/")+glob.glob("*.stl")
|
||||
|
||||
def help_skein(self):
|
||||
print "Creates a gcode file from an stl model using the slicer (with tab-completion)"
|
||||
print "skein filename.stl - create gcode file"
|
||||
print "skein filename.stl view - create gcode file and view using skeiniso"
|
||||
print "skein set - adjust slicer settings"
|
||||
self.log("Creates a gcode file from an stl model using the slicer (with tab-completion)")
|
||||
self.log("skein filename.stl - create gcode file")
|
||||
self.log("skein filename.stl view - create gcode file and view using skeiniso")
|
||||
self.log("skein set - adjust slicer settings")
|
||||
|
||||
|
||||
def do_home(self, l):
|
||||
if not self.p.online:
|
||||
print "Printer is not online. Unable to move."
|
||||
self.log("printer is not online. Unable to move.")
|
||||
return
|
||||
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
|
||||
if "x" in l.lower():
|
||||
self.p.send_now("G28 X0")
|
||||
|
@ -1278,32 +1290,26 @@ class pronsole(cmd.Cmd):
|
|||
self.p.send_now("G92 E0")
|
||||
|
||||
def help_home(self):
|
||||
print "Homes the printer"
|
||||
print "home - homes all axes and zeroes the extruder(Using G28 and G92)"
|
||||
print "home xy - homes x and y axes (Using G28)"
|
||||
print "home z - homes z axis only (Using G28)"
|
||||
print "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("Homes the printer")
|
||||
self.log("home - homes all axes and zeroes the extruder(Using G28 and G92)")
|
||||
self.log("home xy - homes x and y axes (Using G28)")
|
||||
self.log("home z - homes z axis only (Using G28)")
|
||||
self.log("home e - set extruder position to zero (Using G92)")
|
||||
self.log("home xyze - homes all axes and zeroes the extruder (Using G28 and G92)")
|
||||
|
||||
def parse_cmdline(self, args):
|
||||
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:
|
||||
#print repr((o, a))
|
||||
#self.log(repr((o, a)))
|
||||
if o in ("-c", "--conf", "--config"):
|
||||
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"):
|
||||
print "Usage: "+sys.argv[0]+' [-c filename [-c filename2 ... ] ] [-e "command" ...]'
|
||||
print " -c | --conf | --config - override startup .pronsolerc file"
|
||||
print " 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'
|
||||
print " macros/settings from these commands are not autosaved"
|
||||
self.log("Usage: "+sys.argv[0]+' [-c filename [-c filename2 ... ] ] [-e "command" ...]')
|
||||
self.log(" -c | --conf | --config - override startup .pronsolerc file")
|
||||
self.log(" may chain config files, settings auto-save will go into last file in the chain")
|
||||
self.log(' -e <command> - executes command after configuration/.pronsolerc is loaded')
|
||||
self.log(" macros/settings from these commands are not autosaved")
|
||||
sys.exit()
|
||||
if not self.rc_loaded:
|
||||
self.load_default_rc()
|
||||
|
|
|
@ -196,21 +196,6 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
|||
self.predisconnect_layer = None
|
||||
self.hsetpoint = 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:
|
||||
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.")
|
||||
except Exception, 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 = ""):
|
||||
try:
|
||||
|
@ -382,16 +365,10 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
|||
self.setbedgui(f)
|
||||
else:
|
||||
print _("Printer is not online.")
|
||||
if self.webInterface:
|
||||
self.webInterface.AddLog("Printer is not online.")
|
||||
else:
|
||||
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:
|
||||
print _("You must enter a temperature. (%s)") % (repr(x),)
|
||||
if self.webInterface:
|
||||
self.webInterface.AddLog("You must enter a temperature.")
|
||||
|
||||
def end_macro(self):
|
||||
pronsole.pronsole.end_macro(self)
|
||||
|
@ -411,8 +388,6 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
|||
self.delete_macro(macro_name)
|
||||
return
|
||||
print _("Cancelled.")
|
||||
if self.webInterface:
|
||||
self.webInterface.AddLog("Cancelled.")
|
||||
return
|
||||
self.cur_macro_name = macro_name
|
||||
self.cur_macro_def = definition
|
||||
|
@ -452,8 +427,6 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
|||
projectlayer.setframe(self,self.p).Show()
|
||||
else:
|
||||
print _("Printer is not online.")
|
||||
if self.webInterface:
|
||||
self.webInterface.AddLog("Printer is not online.")
|
||||
|
||||
def popmenu(self):
|
||||
self.menustrip = wx.MenuBar()
|
||||
|
@ -530,8 +503,6 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
|||
old_def = self.macros[macro]
|
||||
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")
|
||||
if self.webInterface:
|
||||
self.webInterface.AddLog("Macro name may contain only alphanumeric symbols and underscores")
|
||||
return
|
||||
elif hasattr(self.__class__, "do_"+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):
|
||||
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 nextarg(rest):
|
||||
|
@ -737,8 +706,6 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
|||
command = argstr.strip()
|
||||
if num<0 or num>=64:
|
||||
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
|
||||
while num >= len(self.custombuttons):
|
||||
self.custombuttons.append(None)
|
||||
|
@ -1004,8 +971,6 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
|||
self.cur_button = None
|
||||
except:
|
||||
print _("event object missing")
|
||||
if self.webInterface:
|
||||
self.webInterface.AddLog("event object missing")
|
||||
self.cur_button = None
|
||||
raise
|
||||
|
||||
|
@ -1025,9 +990,6 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
|||
except:
|
||||
pass
|
||||
self.Destroy()
|
||||
if self.webInterface:
|
||||
from printrun import webinterface
|
||||
webinterface.KillWebInterfaceThread()
|
||||
|
||||
def do_monitor(self, l = ""):
|
||||
if l.strip()=="":
|
||||
|
@ -1040,17 +1002,11 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
|||
wx.CallAfter(self.monitorbox.SetValue, self.monitor_interval>0)
|
||||
except:
|
||||
print _("Invalid period given.")
|
||||
if self.webInterface:
|
||||
self.webInterface.AddLog("Invalid period given.")
|
||||
self.setmonitor(None)
|
||||
if self.monitor:
|
||||
print _("Monitoring printer.")
|
||||
if self.webInterface:
|
||||
self.webInterface.AddLog("Monitoring printer.")
|
||||
else:
|
||||
print _("Done monitoring.")
|
||||
if self.webInterface:
|
||||
self.webInterface.AddLog("Done monitoring.")
|
||||
|
||||
def setmonitor(self, e):
|
||||
self.monitor = self.monitorbox.GetValue()
|
||||
|
@ -1065,8 +1021,6 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
|||
except:
|
||||
print "attempted to write invalid text to console"
|
||||
pass
|
||||
if self.webInterface:
|
||||
self.webInterface.AppendLog(text)
|
||||
|
||||
def setloud(self,e):
|
||||
self.p.loud=e.IsChecked()
|
||||
|
@ -1229,8 +1183,6 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
|||
import shlex
|
||||
param = self.expandcommand(self.settings.slicecommand).encode()
|
||||
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())]
|
||||
#print pararray
|
||||
self.skeinp = subprocess.Popen(pararray, stderr = subprocess.STDOUT, stdout = subprocess.PIPE)
|
||||
|
@ -1242,8 +1194,6 @@ class PronterWindow(MainWindow, pronsole.pronsole):
|
|||
self.stopsf = 1
|
||||
except:
|
||||
print _("Failed to execute slicing software: ")
|
||||
if self.webInterface:
|
||||
self.webInterface.AddLog("Failed to execute slicing software: ")
|
||||
self.stopsf = 1
|
||||
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)
|
||||
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)
|
||||
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 Z\nand is %f mm high\n") % (Zmin, Zmax, Ztot)
|
||||
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