Commit f5255cde authored by Guillaume Seguin's avatar Guillaume Seguin

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

parents 5b87f5f3 c04950f3
...@@ -92,6 +92,130 @@ All commands have internal help, which you can access by typing "help commandnam ...@@ -92,6 +92,130 @@ All commands have internal help, which you can access by typing "help commandnam
If you want to load stl files, you need to put a version of skeinforge (doesn't matter which one) in a folder called "skeinforge". If you want to load stl files, you need to put a version of skeinforge (doesn't matter which one) in a folder called "skeinforge".
The "skeinforge" folder must be in the same folder as pronsole.py The "skeinforge" folder must be in the same folder as pronsole.py
# USING MACROS AND CUSTOM BUTTONS
## Macros in pronsole and pronterface
To send simple G-code (or pronsole command) sequence is as simple as entering them one by one in macro definition.
If you want to use parameters for your macros, substitute them with {0} {1} {2} ... etc.
All macros are saved automatically immediately after being entered.
Example 1, simple one-line alias:
PC> macro where M114
Instead of having to remember the code to query position, you can query the position:
PC> where
X:25.00Y:11.43Z:5.11E:0.00
Example 2 - macros to switch between different slicer programs, using "set" command to change options:
PC> macro use_slicer
Enter macro using indented lines, end with empty line
..> set sliceoptscommand Slic3r/slic3r.exe --load slic3r.ini
..> set slicecommand Slic3r/slic3r.exe $s --load slic3r.ini --output $o
Macro 'use_slicer' defined
PC> macro use_sfact
..> set sliceoptscommand python skeinforge/skeinforge_application/skeinforge.py
..> set slicecommand python skeinforge/skeinforge_application/skeinforge_utilities/skeinforge_craft.py $s
Macro 'use_sfact' defined
Example 3, simple parametric macro:
PC> macro move_down_by
Enter macro using indented lines, end with empty line
..> G91
..> G1 Z-{0}
..> G92
..>
Invoke the macro to move the printhead down by 5 millimeters:
PC> move_down_by 5
For more powerful macro programming, it is possible to use python code escaping using ! symbol in front of macro commands.
Note that this python code invocation also works in interactive prompt:
PC> !print "Hello, printer!"
Hello printer!
PC> macro debug_on !self.p.loud = 1
Macro 'debug_on' defined
PC> debug_on
PC> M114
SENT: M114
X:0.00Y:0.00Z:0.00E:0.00 Count X:0.00Y:0.00Z:0.00
RECV: X:0.00Y:0.00Z:0.00E:0.00 Count X:0.00Y:0.00Z:0.00
RECV: ok
You can use macro command itself to create simple self-modify or toggle functionality:
Example: swapping two macros to implement toggle:
PC> macro toggle_debug_on
Enter macro using indented lines, end with empty line
..> !self.p.loud = 1
..> !print "Diagnostic information ON"
..> macro toggle_debug toggle_debug_off
..>
Macro 'toggle_debug_on' defined
PC> macro toggle_debug_off
Enter macro using indented lines, end with empty line
..> !self.p.loud = 0
..> !print "Diagnostic information OFF"
..> macro toggle_debug toggle_debug_on
..>
Macro 'toggle_debug_off' defined
PC> macro toggle_debug toggle_debug_on
Macro 'toggle_debug' defined
Now, each time we invoke "toggle_debug" macro, it toggles debug information on and off:
PC> toggle_debug
Diagnostic information ON
PC> toggle_debug
Diagnostic information OFF
When python code (using ! symbol) is used in macros, it is even possible to use blocks/conditionals/loops.
It is okay to mix python code with pronsole commands, just keep the python indentation.
For example, following macro toggles the diagnostic information similarily to the previous example:
!if self.p.loud:
!self.p.loud = 0
!print "Diagnostic information OFF"
!else:
!self.p.loud = 1
!print "Diagnostic information ON"
Macro parameters are available in '!'-escaped python code as locally defined list variable: arg[0] arg[1] ... arg[N]
All python code is executed in the context of the pronsole (or PronterWindow) object,
so it is possible to use all internal variables and methods, which provide great deal of functionality.
However the internal variables and methods are not very well documented and may be subject of change, as the program is developed.
Therefore it is best to use pronsole commands, which easily contain majority of the functionality that might be needed.
Some useful python-mode-only variables:
!self.settings - contains all settings, e.g.
port (!self.settings.port), baudrate, xy_feedrate, e_feedrate, slicecommand, final_command, build_dimensions
You can set them also via pronsole command "set", but you can query the values only via python code.
!self.p - printcore object (see USING PRINTCORE section for using printcore object)
!self.cur_button - if macro was invoked via custom button, the number of the custom button, e.g. for usage in "button" command
!self.gwindow - wx graphical interface object for pronterface (highly risky to use because the GUI implementation details may change a lot between versions)
Some useful methods:
!self.onecmd - invokes raw command, e.g.
!self.onecmd("move x 10")
!self.onecmd("!print self.p.loud")
!self.onecmd("button "+self.cur_button+" fanOFF /C cyan M107")
!self.project - invoke Projector
# USING PRINTCORE # USING PRINTCORE
To use printcore you need python (ideally 2.6.x or 2.7.x) and pyserial (or python-serial on ubuntu/debian) To use printcore you need python (ideally 2.6.x or 2.7.x) and pyserial (or python-serial on ubuntu/debian)
......
...@@ -146,6 +146,11 @@ class ConstructSocketHandler(tornado.websocket.WebSocketHandler): ...@@ -146,6 +146,11 @@ class ConstructSocketHandler(tornado.websocket.WebSocketHandler):
'jobs': prontserve.jobs.public_list(), 'jobs': prontserve.jobs.public_list(),
'continous_movement': False 'continous_movement': False
}}) }})
# Send events to initialize the machine's state
self.on_sensor_changed()
for k, v in prontserve.target_values.iteritems():
self.on_uncaught_event("target_temp_changed", {k: v})
self.on_uncaught_event("job_progress_changed", prontserve.previous_job_progress)
print "WebSocket opened. %i sockets currently open." % len(prontserve.listeners) print "WebSocket opened. %i sockets currently open." % len(prontserve.listeners)
def send(self, dict_args = {}, **kwargs): def send(self, dict_args = {}, **kwargs):
...@@ -251,13 +256,13 @@ class Prontserve(pronsole.pronsole, EventEmitter): ...@@ -251,13 +256,13 @@ class Prontserve(pronsole.pronsole, EventEmitter):
pronsole.pronsole.__init__(self) pronsole.pronsole.__init__(self)
EventEmitter.__init__(self) EventEmitter.__init__(self)
self.settings.sensor_names = {'T': 'extruder', 'B': 'bed'} self.settings.sensor_names = {'T': 'extruder', 'B': 'bed'}
self.settings.name = 'Prontserve Printer'
self.settings.pause_between_prints = True self.settings.pause_between_prints = True
self.dry_run = kwargs['dry_run'] == True self.dry_run = kwargs['dry_run'] == True
self.stdout = sys.stdout self.stdout = sys.stdout
self.ioloop = tornado.ioloop.IOLoop.instance() self.ioloop = tornado.ioloop.IOLoop.instance()
self.settings.sensor_poll_rate = 1 # seconds self.settings.sensor_poll_rate = 1 # seconds
self.sensors = {'extruder': -1, 'bed': -1} self.sensors = {'extruder': -1, 'bed': -1}
self.target_values = {'e': 0, 'b': 0}
self.load_default_rc() self.load_default_rc()
self.jobs = PrintJobQueue() self.jobs = PrintJobQueue()
self.job_id_incr = 0 self.job_id_incr = 0
...@@ -269,7 +274,7 @@ class Prontserve(pronsole.pronsole, EventEmitter): ...@@ -269,7 +274,7 @@ class Prontserve(pronsole.pronsole, EventEmitter):
self.jobs.listeners.add(self) self.jobs.listeners.add(self)
def init_mdns(self): def init_mdns(self):
sdRef = pybonjour.DNSServiceRegister(name = self.settings.name, sdRef = pybonjour.DNSServiceRegister(name = None,
regtype = '_construct._tcp', regtype = '_construct._tcp',
port = 8888, port = 8888,
domain = "local.") domain = "local.")
...@@ -329,6 +334,9 @@ class Prontserve(pronsole.pronsole, EventEmitter): ...@@ -329,6 +334,9 @@ class Prontserve(pronsole.pronsole, EventEmitter):
print "%stemp %s"%(prefix, kwargs[k]) print "%stemp %s"%(prefix, kwargs[k])
setter = getattr(pronsole.pronsole, "do_%stemp"%prefix) setter = getattr(pronsole.pronsole, "do_%stemp"%prefix)
setter(self, kwargs[k]) setter(self, kwargs[k])
pprint({prefix: kwargs[k]})
self.target_values[k] = kwargs[k]
self.fire("target_temp_changed", {k: kwargs[k]})
def do_set_feedrate(self, **kwargs): def do_set_feedrate(self, **kwargs):
# TODO: kwargs[xy] * 60 and kwargs[z] * 60 # TODO: kwargs[xy] * 60 and kwargs[z] * 60
...@@ -346,7 +354,17 @@ class Prontserve(pronsole.pronsole, EventEmitter): ...@@ -346,7 +354,17 @@ class Prontserve(pronsole.pronsole, EventEmitter):
self.jobs.update(int(job_id), kwargs) self.jobs.update(int(job_id), kwargs)
def do_get_jobs(self): def do_get_jobs(self):
return {'jobs': self.jobs.public_list()} jobexport = []
if self.current_job != None:
jobexport.append(
dict(
id = self.current_job["id"],
file_name = self.current_job["file_name"],
printing = True
)
)
jobexport.extend(self.jobs.public_list())
return {'jobs': jobexport}
def run_print_queue_loop(self): def run_print_queue_loop(self):
# This is a polling work around to the current lack of events in printcore # This is a polling work around to the current lack of events in printcore
...@@ -461,6 +479,7 @@ class PrintJobQueue(EventEmitter): ...@@ -461,6 +479,7 @@ class PrintJobQueue(EventEmitter):
return dict( return dict(
id = job["id"], id = job["id"],
file_name = job["file_name"], file_name = job["file_name"],
printing = False,
) )
def add(self, file_name, body): def add(self, file_name, body):
...@@ -519,32 +538,33 @@ class PrintJobQueue(EventEmitter): ...@@ -519,32 +538,33 @@ class PrintJobQueue(EventEmitter):
# Server Start Up # Server Start Up
# ------------------------------------------------- # -------------------------------------------------
parser = argparse.ArgumentParser( if __name__ == "__main__":
parser = argparse.ArgumentParser(
description='Runs a 3D printer server using the Construct Protocol' description='Runs a 3D printer server using the Construct Protocol'
) )
parser.add_argument('--dry-run', default=False, action='store_true', parser.add_argument('--dry-run', default=False, action='store_true',
help='Does not connect to the 3D printer' help='Does not connect to the 3D printer'
) )
args = parser.parse_args() args = parser.parse_args()
dry_run = args.dry_run dry_run = args.dry_run
def warn_if_dry_run(): def warn_if_dry_run():
if dry_run: if dry_run:
for i in range(0,7): for i in range(0,7):
sys.stdout.write("\x1B[0;33m Dry Run \x1B[0m") sys.stdout.write("\x1B[0;33m Dry Run \x1B[0m")
print "" print ""
print "Prontserve is starting..." print "Prontserve is starting..."
prontserve = Prontserve(dry_run=dry_run) prontserve = Prontserve(dry_run=dry_run)
if dry_run==False: prontserve.do_connect("") if dry_run==False: prontserve.do_connect("")
time.sleep(1) time.sleep(1)
prontserve.run_sensor_loop() prontserve.run_sensor_loop()
prontserve.run_print_queue_loop() prontserve.run_print_queue_loop()
if __name__ == "__main__":
application.listen(8888) application.listen(8888)
print "\n"+"-"*80 print "\n"+"-"*80
welcome = textwrap.dedent(u""" welcome = textwrap.dedent(u"""
......
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