commit
ab9e5516d5
14
README.md
14
README.md
|
@ -4,6 +4,20 @@ Printrun consists of printcore, pronsole and pronterface, and a small collection
|
||||||
* pronsole.py is an interactive command-line host software with tabcompletion goodness
|
* pronsole.py is an interactive command-line host software with tabcompletion goodness
|
||||||
* pronterface.py is a graphical host software with the same functionality as pronsole
|
* pronterface.py is a graphical host software with the same functionality as pronsole
|
||||||
|
|
||||||
|
# Modifications by Beardface (Webinterface)
|
||||||
|
|
||||||
|
## Webinterface Dependencies
|
||||||
|
|
||||||
|
Cherrypy is required for the web interface. In my branch it is available in the libs folder, install by opening a
|
||||||
|
command prompt there and running python setup.py install. You can also download and install from cherrypy.
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
# INSTALLING DEPENDENCIES
|
# INSTALLING DEPENDENCIES
|
||||||
|
|
||||||
## Windows
|
## Windows
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
[user]
|
||||||
|
user = admin
|
||||||
|
pass = password
|
|
@ -0,0 +1,206 @@
|
||||||
|
#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; }
|
|
@ -0,0 +1,4 @@
|
||||||
|
[global]
|
||||||
|
server.socket_host: "localhost"
|
||||||
|
server.socket_port: 8080
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?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() . ")";
|
||||||
|
}
|
||||||
|
?>
|
|
@ -49,11 +49,20 @@ if os.name=="nt":
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
from xybuttons import XYButtons
|
from xybuttons import XYButtons
|
||||||
from zbuttons import ZButtons
|
from zbuttons import ZButtons
|
||||||
from graph import Graph
|
from graph import Graph
|
||||||
import pronsole
|
import pronsole
|
||||||
|
|
||||||
|
webavail = True
|
||||||
|
try :
|
||||||
|
import cherrypy, webinterface
|
||||||
|
from threading import Thread
|
||||||
|
except:
|
||||||
|
print _("CherryPy is not installed. Web Interface Disabled.")
|
||||||
|
webavail = False
|
||||||
|
|
||||||
def dosify(name):
|
def dosify(name):
|
||||||
return os.path.split(name)[1].split(".")[0][:8]+".g"
|
return os.path.split(name)[1].split(".")[0][:8]+".g"
|
||||||
|
|
||||||
|
@ -156,6 +165,10 @@ class PronterWindow(wx.Frame,pronsole.pronsole):
|
||||||
self.cur_button=None
|
self.cur_button=None
|
||||||
self.hsetpoint=0.0
|
self.hsetpoint=0.0
|
||||||
self.bsetpoint=0.0
|
self.bsetpoint=0.0
|
||||||
|
if webavail:
|
||||||
|
self.webInterface=webinterface.WebInterface(self)
|
||||||
|
self.webThread = Thread(target=webinterface.StartWebInterfaceThread, args=(self.webInterface, ))
|
||||||
|
self.webThread.start()
|
||||||
|
|
||||||
def startcb(self):
|
def startcb(self):
|
||||||
self.starttime=time.time()
|
self.starttime=time.time()
|
||||||
|
@ -284,6 +297,8 @@ class PronterWindow(wx.Frame,pronsole.pronsole):
|
||||||
print _("You cannot set negative temperatures. To turn the hotend off entirely, set its temperature to 0.")
|
print _("You cannot set negative temperatures. To turn the hotend off entirely, set its temperature to 0.")
|
||||||
except Exception,x:
|
except Exception,x:
|
||||||
print _("You must enter a temperature. (%s)" % (repr(x),))
|
print _("You must enter a temperature. (%s)" % (repr(x),))
|
||||||
|
if webavail:
|
||||||
|
self.webInterface.AddLog("You must enter a temperature. (%s)" % (repr(x),))
|
||||||
|
|
||||||
def do_bedtemp(self,l=""):
|
def do_bedtemp(self,l=""):
|
||||||
try:
|
try:
|
||||||
|
@ -317,10 +332,16 @@ class PronterWindow(wx.Frame,pronsole.pronsole):
|
||||||
wx.CallAfter(self.btemp.Refresh)
|
wx.CallAfter(self.btemp.Refresh)
|
||||||
else:
|
else:
|
||||||
print _("Printer is not online.")
|
print _("Printer is not online.")
|
||||||
|
if webavail:
|
||||||
|
self.webInterface.AddLog("Printer is not online.")
|
||||||
else:
|
else:
|
||||||
print _("You cannot set negative temperatures. To turn the bed off entirely, set its temperature to 0.")
|
print _("You cannot set negative temperatures. To turn the bed off entirely, set its temperature to 0.")
|
||||||
|
if webavail:
|
||||||
|
self.webInterface.AddLog("You cannot set negative temperatures. To turn the bed off entirely, set its temperature to 0.")
|
||||||
except:
|
except:
|
||||||
print _("You must enter a temperature.")
|
print _("You must enter a temperature.")
|
||||||
|
if webavail:
|
||||||
|
self.webInterface.AddLog("You must enter a temperature.")
|
||||||
|
|
||||||
def end_macro(self):
|
def end_macro(self):
|
||||||
pronsole.pronsole.end_macro(self)
|
pronsole.pronsole.end_macro(self)
|
||||||
|
@ -340,6 +361,8 @@ class PronterWindow(wx.Frame,pronsole.pronsole):
|
||||||
self.delete_macro(macro_name)
|
self.delete_macro(macro_name)
|
||||||
return
|
return
|
||||||
print _("Cancelled.")
|
print _("Cancelled.")
|
||||||
|
if webavail:
|
||||||
|
self.webInterface.AddLog("Cancelled.")
|
||||||
return
|
return
|
||||||
self.cur_macro_name = macro_name
|
self.cur_macro_name = macro_name
|
||||||
self.cur_macro_def = definition
|
self.cur_macro_def = definition
|
||||||
|
@ -358,6 +381,8 @@ class PronterWindow(wx.Frame,pronsole.pronsole):
|
||||||
self.capture_skip_newline = True
|
self.capture_skip_newline = True
|
||||||
return
|
return
|
||||||
wx.CallAfter(self.logbox.AppendText,l)
|
wx.CallAfter(self.logbox.AppendText,l)
|
||||||
|
if webavail:
|
||||||
|
self.webInterface.AppendLog(l)
|
||||||
|
|
||||||
def scanserial(self):
|
def scanserial(self):
|
||||||
"""scan for available ports. return a list of device names."""
|
"""scan for available ports. return a list of device names."""
|
||||||
|
@ -379,6 +404,8 @@ class PronterWindow(wx.Frame,pronsole.pronsole):
|
||||||
projectlayer.setframe(self,self.p).Show()
|
projectlayer.setframe(self,self.p).Show()
|
||||||
else:
|
else:
|
||||||
print _("Printer is not online.")
|
print _("Printer is not online.")
|
||||||
|
if webavail:
|
||||||
|
self.webInterface.AddLog("Printer is not online.")
|
||||||
|
|
||||||
def popmenu(self):
|
def popmenu(self):
|
||||||
self.menustrip = wx.MenuBar()
|
self.menustrip = wx.MenuBar()
|
||||||
|
@ -453,6 +480,8 @@ class PronterWindow(wx.Frame,pronsole.pronsole):
|
||||||
return
|
return
|
||||||
elif len([c for c in macro if not c.isalnum() and c != "_"]):
|
elif len([c for c in macro if not c.isalnum() and c != "_"]):
|
||||||
print _("Macro name may contain only alphanumeric symbols and underscores")
|
print _("Macro name may contain only alphanumeric symbols and underscores")
|
||||||
|
if webavail:
|
||||||
|
self.webInterface.AddLog("Macro name may contain only alphanumeric symbols and underscores")
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
old_def = ""
|
old_def = ""
|
||||||
|
@ -906,6 +935,8 @@ class PronterWindow(wx.Frame,pronsole.pronsole):
|
||||||
|
|
||||||
def help_button(self):
|
def help_button(self):
|
||||||
print _('Defines custom button. Usage: button <num> "title" [/c "colour"] command')
|
print _('Defines custom button. Usage: button <num> "title" [/c "colour"] command')
|
||||||
|
if webavail:
|
||||||
|
self.webInterface.AddLog('Defines custom button. Usage: button <num> "title" [/c "colour"] command')
|
||||||
|
|
||||||
def do_button(self,argstr):
|
def do_button(self,argstr):
|
||||||
def nextarg(rest):
|
def nextarg(rest):
|
||||||
|
@ -928,6 +959,8 @@ class PronterWindow(wx.Frame,pronsole.pronsole):
|
||||||
command=argstr.strip()
|
command=argstr.strip()
|
||||||
if num<0 or num>=64:
|
if num<0 or num>=64:
|
||||||
print _("Custom button number should be between 0 and 63")
|
print _("Custom button number should be between 0 and 63")
|
||||||
|
if webavail:
|
||||||
|
self.webInterface.AddLog("Custom button number should be between 0 and 63")
|
||||||
return
|
return
|
||||||
while num >= len(self.custombuttons):
|
while num >= len(self.custombuttons):
|
||||||
self.custombuttons+=[None]
|
self.custombuttons+=[None]
|
||||||
|
@ -1187,6 +1220,8 @@ class PronterWindow(wx.Frame,pronsole.pronsole):
|
||||||
self.cur_button=None
|
self.cur_button=None
|
||||||
except:
|
except:
|
||||||
print _("event object missing")
|
print _("event object missing")
|
||||||
|
if webavail:
|
||||||
|
self.webInterface.AddLog("event object missing")
|
||||||
self.cur_button=None
|
self.cur_button=None
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
@ -1203,6 +1238,8 @@ class PronterWindow(wx.Frame,pronsole.pronsole):
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
self.Destroy()
|
self.Destroy()
|
||||||
|
if webavail:
|
||||||
|
webinterface.KillWebInterfaceThread()
|
||||||
|
|
||||||
def do_monitor(self,l=""):
|
def do_monitor(self,l=""):
|
||||||
if l.strip()=="":
|
if l.strip()=="":
|
||||||
|
@ -1215,11 +1252,17 @@ class PronterWindow(wx.Frame,pronsole.pronsole):
|
||||||
wx.CallAfter(self.monitorbox.SetValue,self.monitor_interval>0)
|
wx.CallAfter(self.monitorbox.SetValue,self.monitor_interval>0)
|
||||||
except:
|
except:
|
||||||
print _("Invalid period given.")
|
print _("Invalid period given.")
|
||||||
|
if webavail:
|
||||||
|
self.webInterface.AddLog("Invalid period given.")
|
||||||
self.setmonitor(None)
|
self.setmonitor(None)
|
||||||
if self.monitor:
|
if self.monitor:
|
||||||
print _("Monitoring printer.")
|
print _("Monitoring printer.")
|
||||||
|
if webavail:
|
||||||
|
self.webInterface.AddLog("Monitoring printer.")
|
||||||
else:
|
else:
|
||||||
print _("Done monitoring.")
|
print _("Done monitoring.")
|
||||||
|
if webavail:
|
||||||
|
self.webInterface.AddLog("Done monitoring.")
|
||||||
|
|
||||||
|
|
||||||
def setmonitor(self,e):
|
def setmonitor(self,e):
|
||||||
|
@ -1236,6 +1279,8 @@ class PronterWindow(wx.Frame,pronsole.pronsole):
|
||||||
if not len(command):
|
if not len(command):
|
||||||
return
|
return
|
||||||
wx.CallAfter(self.logbox.AppendText,">>>"+command+"\n")
|
wx.CallAfter(self.logbox.AppendText,">>>"+command+"\n")
|
||||||
|
if webavail:
|
||||||
|
self.webInterface.AppendLog(">>>"+command+"\n")
|
||||||
self.onecmd(str(command))
|
self.onecmd(str(command))
|
||||||
self.commandbox.SetSelection(0,len(command))
|
self.commandbox.SetSelection(0,len(command))
|
||||||
|
|
||||||
|
@ -1399,6 +1444,8 @@ class PronterWindow(wx.Frame,pronsole.pronsole):
|
||||||
import shlex
|
import shlex
|
||||||
param = self.expandcommand(self.settings.slicecommand).encode()
|
param = self.expandcommand(self.settings.slicecommand).encode()
|
||||||
print "Slicing: ",param
|
print "Slicing: ",param
|
||||||
|
if webavail:
|
||||||
|
self.webInterface.AddLog("Slicing: "+param)
|
||||||
pararray=[i.replace("$s",self.filename).replace("$o",self.filename.replace(".stl","_export.gcode").replace(".STL","_export.gcode")).encode() for i in shlex.split(param.replace("\\","\\\\").encode())]
|
pararray=[i.replace("$s",self.filename).replace("$o",self.filename.replace(".stl","_export.gcode").replace(".STL","_export.gcode")).encode() for i in shlex.split(param.replace("\\","\\\\").encode())]
|
||||||
#print pararray
|
#print pararray
|
||||||
self.skeinp=subprocess.Popen(pararray,stderr=subprocess.STDOUT,stdout=subprocess.PIPE)
|
self.skeinp=subprocess.Popen(pararray,stderr=subprocess.STDOUT,stdout=subprocess.PIPE)
|
||||||
|
@ -1410,6 +1457,8 @@ class PronterWindow(wx.Frame,pronsole.pronsole):
|
||||||
self.stopsf=1
|
self.stopsf=1
|
||||||
except:
|
except:
|
||||||
print _("Failed to execute slicing software: ")
|
print _("Failed to execute slicing software: ")
|
||||||
|
if webavail:
|
||||||
|
self.webInterface.AddLog("Failed to execute slicing software: ")
|
||||||
self.stopsf=1
|
self.stopsf=1
|
||||||
traceback.print_exc(file=sys.stdout)
|
traceback.print_exc(file=sys.stdout)
|
||||||
|
|
||||||
|
@ -1496,6 +1545,8 @@ class PronterWindow(wx.Frame,pronsole.pronsole):
|
||||||
Xtot,Ytot,Ztot,Xmin,Xmax,Ymin,Ymax,Zmin,Zmax = pronsole.measurements(self.f)
|
Xtot,Ytot,Ztot,Xmin,Xmax,Ymin,Ymax,Zmin,Zmax = pronsole.measurements(self.f)
|
||||||
print pronsole.totalelength(self.f), _("mm of filament used in this print\n")
|
print pronsole.totalelength(self.f), _("mm of filament used in this print\n")
|
||||||
print _("the print goes from %f mm to %f mm in X\nand is %f mm wide\n") % (Xmin, Xmax, Xtot)
|
print _("the print goes from %f mm to %f mm in X\nand is %f mm wide\n") % (Xmin, Xmax, Xtot)
|
||||||
|
if webavail:
|
||||||
|
self.webInterface.AddLog("the print goes from %f mm to %f mm in X\nand is %f mm wide\n") % (Xmin, Xmax, Xtot)
|
||||||
print _("the print goes from %f mm to %f mm in Y\nand is %f mm wide\n") % (Ymin, Ymax, Ytot)
|
print _("the print goes from %f mm to %f mm in Y\nand is %f mm wide\n") % (Ymin, Ymax, Ytot)
|
||||||
print _("the print goes from %f mm to %f mm in Z\nand is %f mm high\n") % (Zmin, Zmax, Ztot)
|
print _("the print goes from %f mm to %f mm in Z\nand is %f mm high\n") % (Zmin, Zmax, Ztot)
|
||||||
print _("Estimated duration (pessimistic): "), pronsole.estimate_duration(self.f)
|
print _("Estimated duration (pessimistic): "), pronsole.estimate_duration(self.f)
|
||||||
|
@ -1762,6 +1813,8 @@ class macroed(wx.Dialog):
|
||||||
self.callback(self.e.GetValue().split("\n"))
|
self.callback(self.e.GetValue().split("\n"))
|
||||||
def close(self,ev):
|
def close(self,ev):
|
||||||
self.Destroy()
|
self.Destroy()
|
||||||
|
if webavail:
|
||||||
|
webinterface.KillWebInterfaceThread()
|
||||||
def unindent(self,text):
|
def unindent(self,text):
|
||||||
self.indent_chars = text[:len(text)-len(text.lstrip())]
|
self.indent_chars = text[:len(text)-len(text.lstrip())]
|
||||||
if len(self.indent_chars)==0:
|
if len(self.indent_chars)==0:
|
||||||
|
|
|
@ -0,0 +1,372 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
import cherrypy, pronterface, re, ConfigParser, threading
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
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</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):
|
||||||
|
config = ConfigParser.SafeConfigParser(allow_no_value=True)
|
||||||
|
config.read('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 href='/connect'>Connect</a></li>\n"
|
||||||
|
pageText+="<li><a href='/disconnect'>Disconnect</a></li>\n"
|
||||||
|
pageText+="<li><a href='/reset'>Reset</a></li>\n"
|
||||||
|
pageText+="<li><a href='/printbutton'>Print</a></li>\n"
|
||||||
|
pageText+="<li><a href='/pausebutton'>Pause</a></li>\n"
|
||||||
|
|
||||||
|
for i in gPronterPtr.cpbuttons:
|
||||||
|
pageText+="<li><a href='/custom/button/"+i[1]+"'>"+i[0]+"</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" coords="8,5,51,48" href="/home/axis/x" alt="X Home" title="X Home" />'
|
||||||
|
pageText+='<area shape="rect" coords="195,6,236,46" href="/home/axis/y" alt="Y Home" title="Y Home" />'
|
||||||
|
pageText+='<area shape="rect" coords="7,192,48,232" href="/home/axis/all" alt="All Home" title="All Home" />'
|
||||||
|
pageText+='<area shape="rect" coords="194,192,235,232" href="/home/axis/z" alt="Z Home" title="Z Home" />'
|
||||||
|
pageText+='<area shape="rect" coords="62,7,185,34" href="/move/axis/y/100" alt="Y 100" title="Y 100" />'
|
||||||
|
pageText+='<area shape="rect" coords="68,34,175,61" href="/move/axis/y/10" alt="Y 10" title="Y 10" />'
|
||||||
|
pageText+='<area shape="rect" coords="80,60,163,84" href="/move/axis/y/1" alt="Y 1" title="Y 1" />'
|
||||||
|
pageText+='<area shape="rect" coords="106,83,138,107" href="/move/axis/y/.1" alt="Y .1" title="Y .1" />'
|
||||||
|
pageText+='<area shape="rect" coords="110,135,142,159" href="/move/axis/y/-.1" alt="Y -.1" title="Y -.1" />'
|
||||||
|
pageText+='<area shape="rect" coords="81,157,169,181" href="/move/axis/y/-1" alt="Y -1" title="Y -1" />'
|
||||||
|
pageText+='<area shape="rect" coords="69,180,178,206" href="/move/axis/y/-10" alt="Y -10" title="Y -10" />'
|
||||||
|
pageText+='<area shape="rect" coords="60,205,186,231" href="/move/axis/y/-100" alt="Y -100" title="Y -100" />'
|
||||||
|
pageText+='<area shape="rect" coords="11,53,37,179" href="/move/axis/x/-100" alt="X -100" title="X -100" />'
|
||||||
|
pageText+='<area shape="rect" coords="210,59,236,185" href="/move/axis/x/100" alt="X 100" title="X 100" />'
|
||||||
|
pageText+='<area shape="rect" coords="38,60,64,172" href="/move/axis/x/-10" alt="X -10" title="X -10" />'
|
||||||
|
pageText+='<area shape="rect" coords="185,66,211,178" href="/move/axis/x/10" alt="X 10" title="X 10" />'
|
||||||
|
pageText+='<area shape="rect" coords="62,84,83,157" href="/move/axis/x/-1" alt="X -1" title="X -1" />'
|
||||||
|
pageText+='<area shape="rect" coords="163,87,187,160" href="/move/axis/x/1" alt="X 1" title="X 1" />'
|
||||||
|
pageText+='<area shape="rect" coords="82,104,110,139" href="/move/axis/x/-.1" alt="X -.1" title="X -.1" />'
|
||||||
|
pageText+='<area shape="rect" coords="137,105,165,140" href="/move/axis/x/.1" alt="X .1" title="X .1" />'
|
||||||
|
|
||||||
|
pageText+="</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" coords="4,35,54,64" href="/move/axis/z/10" alt="Z 10" title="Z 10" />'
|
||||||
|
pageText+='<area shape="rect" coords="4,60,54,89" href="/move/axis/z/1" alt="Z 1" title="Z 1" />'
|
||||||
|
pageText+='<area shape="rect" coords="4,87,54,116" href="/move/axis/z/.1" alt="Z .1" title="Z .1" />'
|
||||||
|
pageText+='<area shape="rect" coords="4,121,54,150" href="/move/axis/z/-.1" alt="Z -.1" title="Z -.1" />'
|
||||||
|
pageText+='<area shape="rect" coords="4,147,54,176" href="/move/axis/z/-1" alt="Z -1" title="Z -1" />'
|
||||||
|
pageText+='<area shape="rect" coords="4,173,54,202" href="/move/axis/z/-10" alt="Z -10" title="Z -10" />'
|
||||||
|
pageText+="</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("http.config")
|
||||||
|
conf = {'/css/style.css': {'tools.staticfile.on': True,
|
||||||
|
'tools.staticfile.filename': os.path.join(current_dir, 'css/style.css'),
|
||||||
|
},
|
||||||
|
'/images/control_xy.png': {'tools.staticfile.on': True,
|
||||||
|
'tools.staticfile.filename': os.path.join(current_dir, 'images/control_xy.png'),
|
||||||
|
},
|
||||||
|
'/images/control_z.png': {'tools.staticfile.on': True,
|
||||||
|
'tools.staticfile.filename': os.path.join(current_dir, 'images/control_z.png'),
|
||||||
|
}}
|
||||||
|
cherrypy.config.update("http.config")
|
||||||
|
cherrypy.quickstart(webInterface, '/', config=conf)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
cherrypy.config.update("http.config")
|
||||||
|
cherrypy.quickstart(WebInterfaceStub())
|
Loading…
Reference in New Issue