Commit ab9e5516 authored by kliment's avatar kliment

Merge pull request #234 from beardface/experimental

Added web interface
parents 97964293 48f82b90
...@@ -4,6 +4,20 @@ Printrun consists of printcore, pronsole and pronterface, and a small collection ...@@ -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
......
[user]
user = admin
pass = password
\ No newline at end of file
#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; }
\ No newline at end of file
[global]
server.socket_host: "localhost"
server.socket_port: 8080
<?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) . "&deg;c<br />";
echo "Bed: " . round($xml->bed, 0) . "&deg;c<br />";
if ($xml->progress != "NA")
{
echo "Progress: " . $xml->progress . "%";
}
}
catch(Exception $e)
{
echo "ERROR:\n" . $e->getMessage(). " (severity " . $e->getCode() . ")";
}
?>
\ No newline at end of file
...@@ -49,11 +49,20 @@ if os.name=="nt": ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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:
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment