Started refactoring to match coding style and simplify things a bit.

master
Gina Häußge 2013-05-21 22:59:13 +02:00
parent 96adc0dc85
commit 38ec0b96b2
5 changed files with 90 additions and 91 deletions

View File

@ -1,59 +1,56 @@
import sys
import datetime import datetime
import time
import math
import re import re
import logging, logging.config import logging
import subprocess import subprocess
import octoprint.printer as printer
import os import os
# right now we're logging a lot of extra information for testing # right now we're logging a lot of extra information for testing
# we might want to comment out some of the logging eventually # we might want to comment out some of the logging eventually
class event_record(object): class event_record(object):
what = None def __init__(self, what, who, action):
who = None self.what = what
action = None self.who = who
self.action = action
# object that handles receiving events and dispatching them to listeners
#
class EventManager(object): class EventManager(object):
"""
Handles receiving events and dispatching them to listeners
"""
def __init__(self): def __init__(self):
self.registered_events = [] self.registered_events = []
self.logger = logging.getLogger(__name__) self.logger = logging.getLogger(__name__)
# Fire an event to anyone listening def fire(self, name, payload=None):
# any object can generate an event and any object can listen """
# pass in the event_name as a string (arbitrary, but case sensitive) Fire an event to anyone listening.
# and any extra data that may pertain to the event
def FireEvent (self,event_name,extra_data=None): Any object can generate an event and any object can listen pass in the event_name as a string (arbitrary, but
self.logger.info ( "Firing event: " + event_name + " (" +str (extra_data)+")") case sensitive) and any extra payload data that may pertain to the event.
for ev in self.registered_events: """
if event_name == ev.what:
self.logger.info ( "Sending action to " + str(ev.who)) self.logger.debug("Firing event: %s (%r)" % (name, payload))
if ev.action != None : for event in self.registered_events:
ev.action (event_name,extra_data) (who, what, action) = event
# else: if name == what:
# self.logger.info ( "events don't match " + str(ev.what)+ " and " + event_name) self.logger.debug("Sending action to %r" % who)
if action is not None:
action(name, payload)
# register a listener to an event -- pass in
# the event name (as a string), the target object
# and the function to call
def Register (self,event_name, target, action):
new_ev =event_record()
new_ev.what = event_name
new_ev.who = target
new_ev.action= action
self.registered_events=self.registered_events+[new_ev]
self.logger.info ("Registered event '"+new_ev.what+"' to invoke '"+str(new_ev.action)+"' on "+str(new_ev.who) )
def unRegister (self,event_name, target, action):
self.registered_events[:] = [e for e in self.registered_events if event_name != e.what or e.action != action or e.who!=target]
def subscribe(self, name, target, action):
"""
Subscribe a listener to an event -- pass in the event name (as a string), the target object
and the callback object
"""
newEvent = (name, target, action)
self.registered_events = self.registered_events.append(newEvent)
self.logger.debug("Registered event \"%s\" to invoke \"%r\" on %r" % (name, action, target))
def unsubscribe (self, event_name, target, action):
self.registered_events[:] = [e for e in self.registered_events if event_name != e.what or e.action != action or e.who != target]
#sample event receiver #sample event receiver
# def event_rec(self,event_name,extra_data): # def event_rec(self,event_name,extra_data):
@ -68,12 +65,13 @@ class event_dispatch(object):
event_string = None event_string = None
command_data = None command_data = None
# object that hooks the event manager to system events, gcode, etc.
# creates listeners to any events defined in the config.yaml settings
class EventResponse(object): class EventResponse(object):
"""
Hooks the event manager to system events, gcode, etc. Creates listeners to any events defined in the settings.
"""
def __init__(self, eventManager,printer): def __init__(self, eventManager,printer):
self.registered_responses= [] self.registered_responses = []
self._eventManager = eventManager self._eventManager = eventManager
self._printer = printer self._printer = printer
self.logger = logging.getLogger(__name__) self.logger = logging.getLogger(__name__)
@ -81,18 +79,19 @@ class EventResponse(object):
def setupEvents(self,s): def setupEvents(self,s):
availableEvents = s.get(["system", "events"]) availableEvents = s.get(["system", "events"])
for ev in availableEvents: for event in availableEvents:
event = event_dispatch() name = event["event"].strip()
event.type = ev["type"].strip() action = event["type"].strip()
event.event_string = ev["event"].strip() data = event["command"]
event.command_data = ev["command"]
self._eventManager.Register ( event.event_string ,self,self.eventRec) self._eventManager.subscribe(event.event_string, self, self.eventRec)
self.registered_responses = self.registered_responses+[event]
self.logger.info ("Registered "+event.type +" event '"+event.event_string+"' to execute '"+event.command_data+"'" ) self.registered_responses = self.registered_responses.append(event)
self.logger.info ( "Registered "+ str(len(self.registered_responses))+" events") self.logger.debug("Registered %s event \"%s\" to execute \"%s\"" % (event.type, event.event_string, event.command_data))
self.logger.debug("Registered %d events" % len(self.registered_responses))
def eventRec (self,event_name, event_data): def eventRec (self,event_name, event_data):
self.logger.info ( "Receieved event: " + event_name + " (" + str(event_data) + ")") self.logger.debug("Received event: %s (%r)" % (event_name, event_data))
self._event_data = event_data self._event_data = event_data
for ev in self.registered_responses: for ev in self.registered_responses:
if ev.event_string == event_name: if ev.event_string == event_name:
@ -101,8 +100,10 @@ class EventResponse(object):
if ev.type == "gcode": if ev.type == "gcode":
self.executeGCode(ev.command_data) self.executeGCode(ev.command_data)
# handle a few regex substs for job data passed to external apps
def doStringProcessing (self, command_string): def doStringProcessing (self, command_string):
"""
Handles a few regex substs for job data passed to external apps
"""
cmd_string_with_params = command_string cmd_string_with_params = command_string
cmd_string_with_params = re.sub("_ZHEIGHT_",str(self._printer._currentZ), cmd_string_with_params) cmd_string_with_params = re.sub("_ZHEIGHT_",str(self._printer._currentZ), cmd_string_with_params)
if self._printer._filename: if self._printer._filename:
@ -129,22 +130,20 @@ class EventResponse(object):
def executeGCode(self,command_string): def executeGCode(self,command_string):
command_string = self.doStringProcessing(command_string) command_string = self.doStringProcessing(command_string)
self.logger.info ("GCode command: " + command_string) self.logger.debug("GCode command: " + command_string)
self._printer.commands(command_string.split(',')) self._printer.commands(command_string.split(','))
def executeSystemCommand(self,command_string): def executeSystemCommand(self, command_string):
if command_string is None: if command_string is None:
return return
try: try:
command_string = self.doStringProcessing(command_string) command_string = self.doStringProcessing(command_string)
self.logger.info ("Executing system command: "+ command_string) self.logger.info("Executing system command: %s" % command_string)
#use Popen here since it won't wait for the shell to return...and we send some of these #use Popen here since it won't wait for the shell to return...and we send some of these
# commands during a print job, we don't want to block! # commands during a print job, we don't want to block!
subprocess.Popen(command_string,shell = True) subprocess.Popen(command_string, shell=True)
except subprocess.CalledProcessError, e: except subprocess.CalledProcessError, e:
self.logger.warn("Command failed with return code %i: %s" % (e.returncode, e.message)) self.logger.warn("Command failed with return code %i: %s" % (e.returncode, e.message))
except Exception, ex: except Exception, ex:
self.logger.exception("Command failed") self.logger.exception("Command failed")

View File

@ -196,7 +196,7 @@ class Printer():
self._setCurrentZ(-1) self._setCurrentZ(-1)
self._eventManager.FireEvent ('PrintStarted',filename) self._eventManager.fire ('PrintStarted',filename)
self._comm.printGCode(self._gcodeList) self._comm.printGCode(self._gcodeList)
@ -369,11 +369,11 @@ class Printer():
self._timelapse.onPrintjobStarted(self._filename) self._timelapse.onPrintjobStarted(self._filename)
if state == self._comm.STATE_PRINTING and oldState != self._comm.STATE_PAUSED: if state == self._comm.STATE_PRINTING and oldState != self._comm.STATE_PAUSED:
self._eventManager.FireEvent ('PrintStarted',filename) self._eventManager.fire ('PrintStarted',filename)
if state == self._comm.STATE_OPERATIONAL and (oldState <= self._comm.STATE_CONNECTING or oldState >=self._comm.STATE_CLOSED): if state == self._comm.STATE_OPERATIONAL and (oldState <= self._comm.STATE_CONNECTING or oldState >=self._comm.STATE_CLOSED):
self._eventManager.FireEvent ('Connected',self._comm._port+" at " +self._comm._baudrate) self._eventManager.fire ('Connected',self._comm._port+" at " +self._comm._baudrate)
if state == self._comm.STATE_ERROR or state == self._comm.STATE_CLOSED_WITH_ERROR: if state == self._comm.STATE_ERROR or state == self._comm.STATE_CLOSED_WITH_ERROR:
self._eventManager.FireEvent ('Error',self._comm.getErrorString()) self._eventManager.fire ('Error',self._comm.getErrorString())
# forward relevant state changes to gcode manager # forward relevant state changes to gcode manager
if self._comm is not None and oldState == self._comm.STATE_PRINTING: if self._comm is not None and oldState == self._comm.STATE_PRINTING:
@ -382,10 +382,10 @@ class Printer():
#hrm....we seem to hit this state and THEN the next failed state on a cancel request? #hrm....we seem to hit this state and THEN the next failed state on a cancel request?
# oh well, add a check to see if we're really done before sending the success event external command # oh well, add a check to see if we're really done before sending the success event external command
if self._printTimeLeft < 1: if self._printTimeLeft < 1:
self._eventManager.FireEvent ('PrintDone',filename) self._eventManager.fire ('PrintDone',filename)
elif state == self._comm.STATE_CLOSED or state == self._comm.STATE_ERROR or state == self._comm.STATE_CLOSED_WITH_ERROR: elif state == self._comm.STATE_CLOSED or state == self._comm.STATE_ERROR or state == self._comm.STATE_CLOSED_WITH_ERROR:
self._gcodeManager.printFailed(self._filename) self._gcodeManager.printFailed(self._filename)
self._eventManager.FireEvent ('PrintFailed',filename) self._eventManager.fire ('PrintFailed',filename)
self._gcodeManager.resumeAnalysis() # do not analyse gcode while printing self._gcodeManager.resumeAnalysis() # do not analyse gcode while printing
elif self._comm is not None and state == self._comm.STATE_PRINTING: elif self._comm is not None and state == self._comm.STATE_PRINTING:
self._gcodeManager.pauseAnalysis() # printing done, put those cpu cycles to good use self._gcodeManager.pauseAnalysis() # printing done, put those cpu cycles to good use
@ -424,7 +424,7 @@ class Printer():
self.peakZ = newZ self.peakZ = newZ
if self._timelapse is not None: if self._timelapse is not None:
self._timelapse.onZChange(oldZ, newZ) self._timelapse.onZChange(oldZ, newZ)
self._eventManager.FireEvent ('ZChange',newZ) self._eventManager.fire ('ZChange',newZ)
self._setCurrentZ(newZ) self._setCurrentZ(newZ)
@ -442,7 +442,7 @@ class Printer():
self._setCurrentZ(None) self._setCurrentZ(None)
self._setProgressData(None, None, None) self._setProgressData(None, None, None)
self._gcodeLoader = None self._gcodeLoader = None
self.eventManager.FireEvent("LoadDone",filename) self.eventManager.fire("LoadDone",filename)
self._stateMonitor.setGcodeData({"filename": None, "progress": None}) self._stateMonitor.setGcodeData({"filename": None, "progress": None})
self._stateMonitor.setState({"state": self._state, "stateString": self.getStateString(), "flags": self._getStateFlags()}) self._stateMonitor.setState({"state": self._state, "stateString": self.getStateString(), "flags": self._getStateFlags()})

View File

@ -59,7 +59,7 @@ class PrinterStateConnection(tornadio2.SocketConnection):
def on_open(self, info): def on_open(self, info):
global eventManager global eventManager
eventManager.FireEvent("ClientOpen") eventManager.fire("ClientOpen")
self._logger.info("New connection from client") self._logger.info("New connection from client")
# Use of global here is smelly # Use of global here is smelly
printer.registerCallback(self) printer.registerCallback(self)
@ -67,7 +67,7 @@ class PrinterStateConnection(tornadio2.SocketConnection):
def on_close(self): def on_close(self):
global eventManager global eventManager
eventManager.FireEvent("ClientClosed") eventManager.fire("ClientClosed")
self._logger.info("Closed client connection") self._logger.info("Closed client connection")
# Use of global here is smelly # Use of global here is smelly
printer.unregisterCallback(self) printer.unregisterCallback(self)
@ -152,7 +152,7 @@ def connect():
printer.connect(port=port, baudrate=baudrate) printer.connect(port=port, baudrate=baudrate)
elif "command" in request.values.keys() and request.values["command"] == "disconnect": elif "command" in request.values.keys() and request.values["command"] == "disconnect":
printer.disconnect() printer.disconnect()
eventManager.FireEvent("Disconnected") eventManager.fire("Disconnected")
return jsonify(SUCCESS) return jsonify(SUCCESS)
@ -188,10 +188,10 @@ def printJobControl():
printer.startPrint() printer.startPrint()
elif request.values["command"] == "pause": elif request.values["command"] == "pause":
printer.togglePausePrint() printer.togglePausePrint()
eventManager.FireEvent("Paused") eventManager.fire("Paused")
elif request.values["command"] == "cancel": elif request.values["command"] == "cancel":
printer.cancelPrint() printer.cancelPrint()
eventManager.FireEvent("Cancelled") eventManager.fire("Cancelled")
return jsonify(SUCCESS) return jsonify(SUCCESS)
@app.route(BASEURL + "control/temperature", methods=["POST"]) @app.route(BASEURL + "control/temperature", methods=["POST"])
@ -282,7 +282,7 @@ def uploadGcodeFile():
file = request.files["gcode_file"] file = request.files["gcode_file"]
filename = gcodeManager.addFile(file) filename = gcodeManager.addFile(file)
global eventManager global eventManager
eventManager.FireEvent("Upload",filename) eventManager.fire("Upload",filename)
return jsonify(files=gcodeManager.getAllFileData(), filename=filename) return jsonify(files=gcodeManager.getAllFileData(), filename=filename)
@app.route(BASEURL + "gcodefiles/load", methods=["POST"]) @app.route(BASEURL + "gcodefiles/load", methods=["POST"])
@ -296,7 +296,7 @@ def loadGcodeFile():
if filename is not None: if filename is not None:
printer.loadGcode(filename, printAfterLoading) printer.loadGcode(filename, printAfterLoading)
global eventManager global eventManager
eventManager.FireEvent("LoadStart",filename) eventManager.fire("LoadStart",filename)
return jsonify(SUCCESS) return jsonify(SUCCESS)
@app.route(BASEURL + "gcodefiles/delete", methods=["POST"]) @app.route(BASEURL + "gcodefiles/delete", methods=["POST"])
@ -715,7 +715,7 @@ class Server():
self._server = HTTPServer(self._tornado_app) self._server = HTTPServer(self._tornado_app)
self._server.listen(self._port, address=self._host) self._server.listen(self._port, address=self._host)
eventManager.FireEvent("Startup") eventManager.fire("Startup")
IOLoop.instance().start() IOLoop.instance().start()
def _createSocketConnection(self, session, endpoint=None): def _createSocketConnection(self, session, endpoint=None):

View File

@ -86,7 +86,7 @@ class Timelapse(object):
filename = os.path.join(self._captureDir, "tmp_%05d.jpg" % (self._imageNumber)) filename = os.path.join(self._captureDir, "tmp_%05d.jpg" % (self._imageNumber))
self._imageNumber += 1 self._imageNumber += 1
self._logger.debug("Capturing image to %s" % filename) self._logger.debug("Capturing image to %s" % filename)
self._eventManager.FireEvent("CaptureStart",filename); self._eventManager.fire("CaptureStart",filename);
captureThread = threading.Thread(target=self._captureWorker, kwargs={"filename": filename}) captureThread = threading.Thread(target=self._captureWorker, kwargs={"filename": filename})
captureThread.daemon = True captureThread.daemon = True
captureThread.start() captureThread.start()
@ -94,7 +94,7 @@ class Timelapse(object):
def _captureWorker(self, filename): def _captureWorker(self, filename):
urllib.urlretrieve(self._snapshotUrl, filename) urllib.urlretrieve(self._snapshotUrl, filename)
self._logger.debug("Image %s captured from %s" % (filename, self._snapshotUrl)) self._logger.debug("Image %s captured from %s" % (filename, self._snapshotUrl))
self._eventManager.FireEvent("CaptureDone",filename); self._eventManager.fire("CaptureDone",filename);
def _createMovie(self): def _createMovie(self):
ffmpeg = settings().get(["webcam", "ffmpeg"]) ffmpeg = settings().get(["webcam", "ffmpeg"])
@ -124,7 +124,7 @@ class Timelapse(object):
command.append(output) command.append(output)
subprocess.call(command) subprocess.call(command)
self._logger.debug("Rendering movie to %s" % output) self._logger.debug("Rendering movie to %s" % output)
self._eventManager.FireEvent("MovieDone",output); self._eventManager.fire("MovieDone",output);
def cleanCaptureDir(self): def cleanCaptureDir(self):
if not os.path.isdir(self._captureDir): if not os.path.isdir(self._captureDir):

View File

@ -478,30 +478,30 @@ class MachineCom(object):
# some useful event triggered from GCode commands # some useful event triggered from GCode commands
# pause for user input. M0 in Marlin and M1 in G-code standard RS274NGC # pause for user input. M0 in Marlin and M1 in G-code standard RS274NGC
if re.search ("^\s*M226\D",t_cmd,re.I) or re.search ("^\s*M[01]\D",t_cmd,re.I): if re.search ("^\s*M226\D",t_cmd,re.I) or re.search ("^\s*M[01]\D",t_cmd,re.I):
self._eventManager.FireEvent ('Waiting') self._eventManager.fire ('Waiting')
# part cooler started # part cooler started
if re.search ("^\s*M245\D",t_cmd,re.I): if re.search ("^\s*M245\D",t_cmd,re.I):
self._eventManager.FireEvent ('Cooling') self._eventManager.fire ('Cooling')
# part conveyor started # part conveyor started
if re.search ("^\s*M240\D",t_cmd,re.I): if re.search ("^\s*M240\D",t_cmd,re.I):
self._eventManager.FireEvent ('Conveyor') self._eventManager.fire ('Conveyor')
# part ejector # part ejector
if re.search ("^\s*M40\D",t_cmd,re.I): if re.search ("^\s*M40\D",t_cmd,re.I):
self._eventManager.FireEvent ('Eject') self._eventManager.fire ('Eject')
# user alert issued by sending beep command to printer... # user alert issued by sending beep command to printer...
if re.search ("^\s*M300\D",t_cmd,re.I): if re.search ("^\s*M300\D",t_cmd,re.I):
self._eventManager.FireEvent ('Alert') self._eventManager.fire ('Alert')
# Print head has moved to home # Print head has moved to home
if re.search ("^\s*G28\D",t_cmd,re.I): if re.search ("^\s*G28\D",t_cmd,re.I):
self._eventManager.FireEvent ('Home') self._eventManager.fire ('Home')
if re.search ("^\s*M112\D",t_cmd,re.I): if re.search ("^\s*M112\D",t_cmd,re.I):
self._eventManager.FireEvent ('EStop') self._eventManager.fire ('EStop')
if re.search ("^\s*M80\D",t_cmd,re.I): if re.search ("^\s*M80\D",t_cmd,re.I):
self._eventManager.FireEvent ('PowerOn') self._eventManager.fire ('PowerOn')
if re.search ("^\s*M81\D",t_cmd,re.I): if re.search ("^\s*M81\D",t_cmd,re.I):
self._eventManager.FireEvent ('PowerOff') self._eventManager.fire ('PowerOff')
if re.search ("^\s*M25\D",t_cmd,re.I): # SD Card pause if re.search ("^\s*M25\D",t_cmd,re.I): # SD Card pause
self._eventManager.FireEvent ('Paused') self._eventManager.fire ('Paused')
# these comparisons assume that the searched-for string is not in a comment or a parameter, for example # these comparisons assume that the searched-for string is not in a comment or a parameter, for example