def __init__(self, jog_response_file, gcs = None, config = None, logger = None): if not config: self.config = ConfigService() else: self.config = config if not gcs: self.gcs = GCodeServiceClient() else: self.gcs = gcs if logger: self.log = logger else: self.log = logging.getLogger('Jog') ch = logging.StreamHandler() ch.setLevel(logging.DEBUG) formatter = logging.Formatter("%(levelname)s : %(message)s") ch.setFormatter(formatter) self.log.addHandler(ch) self.jog_response_file = jog_response_file # Erase content of jog_response_file open(jog_response_file, 'w').close() self.backtrack = int(self.config.get('jog', 'backtrack', 20)) self.response = {} self.tokens = [] self.cq = queue.Queue() self.running = False self.send_thread = None
def main(): # Setup arguments parser = argparse.ArgumentParser() parser.add_argument("-L", "--log", help="Use logfile to store log messages.", default='<stdout>') parser.add_argument("-p", "--pidfile", help="File to store process pid.", default=os.path.join(RUN_PATH, 'xmlrpcserver.pid')) # Get arguments args = parser.parse_args() pidfile = args.pidfile with open(pidfile, 'w') as f: f.write(str(os.getpid())) time.sleep(2) gcs = GCodeServiceClient() config = ConfigService() rpc = create(gcs, config, args.log) rpc.start() rpc.loop()
def __init__(self, arch='armhf', mcu='atmega1280', notify_update=None, config=None, gcs=None): self.config = config if not config: self.config = ConfigService() if not gcs: self.gcs = GCodeServiceClient() else: self.gcs = gcs self.arch = arch self.mcu = mcu self.remote = RemoteVersion(arch, mcu, config=config) self.tasks = [] self.notify_update = notify_update self.reboot_required = False self.status = '' self.task = ''
def main(): from ws4py.client.threadedclient import WebSocketClient from fabtotum.fabui.notify import NotifyService from fabtotum.utils.pyro.gcodeclient import GCodeServiceClient from fabtotum.fabui.config import ConfigService from fabtotum.os.paths import RUN_PATH import logging import argparse import os # Setup arguments parser = argparse.ArgumentParser() parser.add_argument("-L", "--log", help="Use logfile to store log messages.", default='/var/log/fabui/gpiomonitor.log') parser.add_argument("-p", "--pidfile", help="File to store process pid.", default=os.path.join(RUN_PATH, 'gpiomonitor.pid') ) # Get arguments args = parser.parse_args() pidfile = args.pidfile with open(pidfile, 'w') as f: f.write( str(os.getpid()) ) config = ConfigService() # Load configuration NOTIFY_FILE = config.get('general', 'notify_file') ################################################################## SOCKET_HOST = config.get('socket', 'host') SOCKET_PORT = config.get('socket', 'port') ################################################################## EVENT_PIN = config.get('totumduino', 'event_pin') # Pyro GCodeService wrapper gcs = GCodeServiceClient() ws = WebSocketClient('ws://'+SOCKET_HOST +':'+SOCKET_PORT+'/') ws.connect(); # Notification service ns = NotifyService(ws, NOTIFY_FILE, config) # Setup logger logger2 = logging.getLogger('GPIOMonitor') logger2.setLevel(logging.DEBUG) fh = logging.FileHandler(args.log, mode='w') #~ formatter = logging.Formatter("%(name)s - %(levelname)s : %(message)s") formatter = logging.Formatter("[%(asctime)s] %(levelname)s : %(message)s") fh.setFormatter(formatter) fh.setLevel(logging.DEBUG) logger2.addHandler(fh) gpioMonitor = GPIOMonitor(ns, gcs, logger2, EVENT_PIN) gpioMonitor.start() gpioMonitor.loop()
def __init__(self, stats_file, gcs=None, config=None, logger=None): if not gcs: self.gcs = GCodeServiceClient() else: self.gcs = gcs if not config: self.config = ConfigService() else: self.config = config if logger: self.log = logger else: self.log = logging.getLogger('StatsMonitor') ch = logging.StreamHandler() ch.setLevel(logging.DEBUG) formatter = logging.Formatter("%(levelname)s : %(message)s") ch.setFormatter(formatter) self.log.addHandler(ch) self.stats_file = stats_file self.running = False self.monitor_thread = None self.monitor_write_thread = None self.ev_update = Event() self.backtrack = int(self.config.get('monitor', 'backtrack', 20)) self.update_period = float(self.config.get('monitor', 'period')) ## Monitor variables, fill arrays with zeros self.ext_temp = [0.0] * self.backtrack self.ext_temp_target = [0.0] * self.backtrack self.bed_temp = [0.0] * self.backtrack self.bed_temp_target = [0.0] * self.backtrack self.delta = [0] * self.backtrack self.last_update_time = time.time() # re #~ self.re_temp = re.compile('ok\sT:(?P<T>[0-9]+\.[0-9]+)\s\/(?P<TT>[0-9]+\.[0-9]+)\sB:(?P<B>[0-9]+\.[0-9]+)\s\/(?P<BT>[0-9]+\.[0-9]+)\s') self.config.register_callback(self.__reload_config)
def test_case(): from fabtotum.utils.pyro.gcodeclient import GCodeServiceClient # Pyro GCodeService wrapper gcs = GCodeServiceClient() # Failure RETR = 1 print ">> G0" reply = gcs.send('G0') if reply: print "<<", " ".join(reply) if reply[0] == 'ok': # Success print _("Totumduino link is working.") RETR = 0 # Result exit(RETR)
def __init__(self, log_trace, monitor_file = None, gcs = None, use_callback = True): self.config = ConfigService() self.monitor_file = monitor_file self.trace_file = log_trace self.monitor_lock = RLock() self.monitor_info = { "progress" : 0.0, "paused" : False, "print_started" : False, "started" : time.time(), "auto_shutdown" : False, "completed" : False, "completed_time" : 0, "layer_count" : 0, "current_layer" : 0, "filename" : "", "task_id" : 0, "ext_temp" : 0.0, "ext_temp_target" : 0.0, "bed_temp" : 0.0, "bed_temp_target" : 0.0, "z_override" : 0.0, "rpm" : 0.0, "laser" : 0.0, "fan" : 0.0, "speed" : 100.0, "flow_rate" : 100.0, "tip" : False, "message" : '', "current_line_number" : 0, "gcode_info" : None } if not gcs: self.gcs = GCodeServiceClient() else: self.gcs = gcs if use_callback: self.gcs.register_callback(self.callback_handler) self.macro_error = 0 self.macro_warning = 0 self.macro_skipped = 0 self.progress_monitor = None logging.basicConfig( filename=log_trace, level=logging.INFO, format='%(message)s')
class Jog: def __init__(self, jog_response_file, gcs = None, config = None, logger = None): if not config: self.config = ConfigService() else: self.config = config if not gcs: self.gcs = GCodeServiceClient() else: self.gcs = gcs if logger: self.log = logger else: self.log = logging.getLogger('Jog') ch = logging.StreamHandler() ch.setLevel(logging.DEBUG) formatter = logging.Formatter("%(levelname)s : %(message)s") ch.setFormatter(formatter) self.log.addHandler(ch) self.jog_response_file = jog_response_file # Erase content of jog_response_file open(jog_response_file, 'w').close() self.backtrack = int(self.config.get('jog', 'backtrack', 20)) self.response = {} self.tokens = [] self.cq = queue.Queue() self.running = False self.send_thread = None def __add_token(self, token): to_remove = [] if len(self.tokens) < self.backtrack: if token not in self.tokens: self.tokens.append(token) else: if token not in self.tokens: to_remove.append( self.tokens[0] ) self.tokens = self.tokens[1:] + [token] return to_remove def __send_thread(self): self.log.debug("Jog thread: started") with open(self.jog_response_file, 'w') as f: f.write(json.dumps(self.response) ) while self.running: cmd = self.cq.get() if cmd.id == Command.KILL: break elif cmd.id == Command.CLEAR: self.response = {} elif cmd.id == Command.GCODE: token = cmd.data[0] gcode = cmd.data[1] #~ reply = self.gcs.send(gcode, group = 'jog:{0}'.format(token) ) #~ self.log.debug("jog.send [%s]", gcode) reply = self.gcs.send(gcode, group = 'jog' ) #~ for ln in reply: #~ self.log.debug("jog.reply [%s] : %s", gcode, ln) #print "jog:", reply # self.tokens to_remove = self.__add_token(token) for tok in to_remove: if tok in self.response: del self.response[tok] self.response[token] = {'code': gcode, 'reply': reply} print self.response with open(self.jog_response_file, 'w') as f: f.write(json.dumps(self.response) ) self.log.debug("Jog thread: stopped") ### API ### def is_running(self): """ Returns `True` if the service is running """ return self.running def start(self): """ Start the service. """ self.running = True self.send_thread = Thread( name = "Jog-send", target = self.__send_thread ) self.send_thread.start() def clear(self): """ Clear response file """ self.cq.put( Command.clear() ) def stop(self): """ Stop the service. """ self.running = False # Used to wake up send_thread so it can detect the condition self.cq.put( Command.kill() ) def loop(self): """ Loop until the service is stopped. """ if self.send_thread: self.send_thread.join() def send(self, token, gcode): """ Send a gcode command and write the reply to jog_response_file. :param token: ID used to pair gcode command and reply :param gcode: Gcode to send :type token: string :type gcode: string """ self.cq.put( Command.gcode(token, gcode) )
class StatsMonitor: MAX_DELTA_TIME = 60 # Maximum allowed delta time def __init__(self, stats_file, gcs=None, config=None, logger=None): if not gcs: self.gcs = GCodeServiceClient() else: self.gcs = gcs if not config: self.config = ConfigService() else: self.config = config if logger: self.log = logger else: self.log = logging.getLogger('StatsMonitor') ch = logging.StreamHandler() ch.setLevel(logging.DEBUG) formatter = logging.Formatter("%(levelname)s : %(message)s") ch.setFormatter(formatter) self.log.addHandler(ch) self.stats_file = stats_file self.running = False self.monitor_thread = None self.monitor_write_thread = None self.ev_update = Event() self.backtrack = int(self.config.get('monitor', 'backtrack', 20)) self.update_period = float(self.config.get('monitor', 'period')) ## Monitor variables, fill arrays with zeros self.ext_temp = [0.0] * self.backtrack self.ext_temp_target = [0.0] * self.backtrack self.bed_temp = [0.0] * self.backtrack self.bed_temp_target = [0.0] * self.backtrack self.delta = [0] * self.backtrack self.last_update_time = time.time() # re #~ self.re_temp = re.compile('ok\sT:(?P<T>[0-9]+\.[0-9]+)\s\/(?P<TT>[0-9]+\.[0-9]+)\sB:(?P<B>[0-9]+\.[0-9]+)\s\/(?P<BT>[0-9]+\.[0-9]+)\s') self.config.register_callback(self.__reload_config) def __reload_config(self): old_backtrack = self.backtrack self.backtrack = int(self.config.get('monitor', 'backtrack')) self.update_period = float(self.config.get('monitor', 'period')) if old_backtrack != self.backtrack: self.ext_temp = [0.0] * self.backtrack self.ext_temp_target = [0.0] * self.backtrack self.bed_temp = [0.0] * self.backtrack self.bed_temp_target = [0.0] * self.backtrack self.delta = [0] * self.backtrack self.last_update_time = time.time() #~ def __parse_temperature(self, line): #~ match = self.re_temp.search(line) #~ if match: #~ return ( match.group('T'), match.group('TT'), match.group('B'), match.group('BT') ) @staticmethod def __rotate_values(value_list, new_value=None): if new_value == None: new_value = value_list[-1] return value_list[1:] + [new_value] def __update_values(self, ext_temp=None, ext_temp_target=None, bed_temp=None, bed_temp_target=None): """ Update all values and delta. """ delta = time.time() - self.last_update_time if delta > StatsMonitor.MAX_DELTA_TIME: delta = StatsMonitor.MAX_DELTA_TIME self.ext_temp = self.__rotate_values(self.ext_temp, ext_temp) self.ext_temp_target = self.__rotate_values(self.ext_temp_target, ext_temp_target) self.bed_temp = self.__rotate_values(self.bed_temp, bed_temp) self.bed_temp_target = self.__rotate_values(self.bed_temp_target, bed_temp_target) self.delta = self.__rotate_values(self.delta, delta) self.last_update_time = time.time() # Trigger write operation self.ev_update.set() def __write_thread(self): """ Thread to handle write_stats from a single location. """ self.log.debug("StatsMonitor write thread: started [{0}]".format( self.update_period)) while self.running: # Used both as a delay and event trigger if self.ev_update.wait(self.update_period): # There was an update event, so write the new data self.__write_stats() self.ev_update.clear() #self.__write_stats() self.log.debug("StatsMonitor write thread: stopped") def __monitor_thread(self): """ Thread for periodic temperature reading. """ self.log.debug("StatsMonitor thread: started") while self.running: # Get temperature # Timeout is to prevent waiting for too long when there is a long running # command like M109,M190,G29 or G28 #~ reply = self.gcs.send('M105', group = 'monitor', timeout = 2) reply = self.gcs.send('M105', group='monitor', block=True) if reply != None: # No timeout occured try: #a, b, c, d = self.__parse_temperature(reply[0]) temps = parseM105(reply) if temps: a = temps['T'] b = temps['target']['T'] c = temps['B'] d = temps['target']['B'] self.__update_values(a, b, c, d) # with this one there is too much callback threads on the queue # self.gcs.push("temp_change:all", [a, b, c, d]) except Exception as e: self.log.debug("MONITOR: M105 error, %s", str(e)) else: self.log.debug("MONITOR: M105 aborted") # Wait for the specified period of time before reading temp again time.sleep(self.update_period) self.log.debug("StatsMonitor thread: stopped") def __temp_change_callback(self, action, data): """ Capture asynchronous temperature updates during M109 and M190. """ if action == 'ext_bed': self.log.debug("Ext: %f, Bed: %f", float(data[0]), float(data[1])) self.__update_values(ext_temp=float(data[0]), bed_temp=float(data[1])) elif action == 'all': self.log.debug("Ext: %f/%f, Bed: %f/%f", float(data[0]), float(data[1]), float(data[2]), float(data[3])) self.__update_values(float(data[0]), float(data[1]), float(data[2]), float(data[3])) elif action == 'bed': self.log.debug("Bed: %f", float(data[0])) self.__update_values(bed_temp=float(data[0])) elif action == 'ext': self.log.debug("Ext: %f", float(data[0])) self.__update_values(ext_temp=float(data[0])) def __gcode_action_callback(self, action, data): """ Capture asynchronous events that modify temperature. """ if action == 'heating': if data[0] == 'M109': self.__update_values(ext_temp_target=float(data[1])) elif data[0] == 'M190': self.__update_values(bed_temp_target=float(data[1])) elif data[0] == 'M104': self.__update_values(ext_temp_target=float(data[1])) elif data[0] == 'M140': self.__update_values(bed_temp_target=float(data[1])) def __callback_handler(self, action, data): """ General callback handler. """ if action.startswith('temp_change'): self.__temp_change_callback(action.split(':')[1], data) elif action.startswith('gcode_action'): self.__gcode_action_callback(action.split(':')[1], data) def __write_stats(self): """ Write stats to the stats_file. """ stats = { 'ext_temp': self.ext_temp, 'ext_temp_target': self.ext_temp_target, 'bed_temp': self.bed_temp, 'bed_temp_target': self.bed_temp_target, 'delta': self.delta } with open(self.stats_file, 'w') as f: f.write(json.dumps(stats)) ### API ### def set_backtrack_size(self, size): # TODO: if self.backtrack != size: # resize pass self.backtrack = size def start(self): self.running = True self.gcs.register_callback(self.__callback_handler) self.monitor_thread = Thread(name="Monitor", target=self.__monitor_thread) self.monitor_thread.start() self.monitor_write_thread = Thread(name="Monitor_write", target=self.__write_thread) self.monitor_write_thread.start() def loop(self): if self.monitor_thread: self.monitor_thread.join() def stop(self): self.running = False self.ev_update.set()
def test_case(): from fabtotum.utils.pyro.gcodeclient import GCodeServiceClient from fabtotum.fabui.config import ConfigService from selftests_common import getEndstopValues, getFrontPanelStatus # Pyro GCodeService wrapper gcs = GCodeServiceClient() config = ConfigService() try: safety_door = config.get('settings', 'safety.door') except KeyError: safety_door = 0 try: switch = config.get('settings', 'switch') except KeyError: switch = 0 try: bed_enabled = config.get('settings', 'hardware')['bed']['enable'] except KeyError: bed_enabled = True #################################################################### RETR = 0 # Read 24VDC reply = gcs.send("M751") if reply: #V_24V:24.562 V try: V = float(reply[0].split(':')[1].split()[0]) if V > 19.200 and V < 28.800: print _( "[V] PSU Voltage nominal 24V DC (+/-20% tolerance): {0}V" ).format(V) else: print _( "CRITICAL: PSU Voltage anomaly. Expected 24V DC +/-20%, got : {0}V" ).format(V) RETR = 1 except: print _("No response for M751") RETR = 1 else: print _("No response for M751") RETR = 1 # Read 5VDC reply = gcs.send("M752") if reply: #V_5V:4.979 V try: V = float(reply[0].split(':')[1].split()[0]) if V > 4.0 and V < 6.0: print _( "[V] 5V DC Power Supply is Nominal (+/-20% tolerance): {0}V" ).format(V) else: print _( "CRITICAL: 5V DC Power Supply anomaly. Expected 5V DC +/-20%, got : {0}V" ).format(V) RETR = 1 except: print _("No response for M752") RETR = 1 else: print _("No response for M752") RETR = 1 # Read Current reply = gcs.send("M753") if reply: #Isinked:0.000 A try: A = float(reply[0].split(':')[1].split()[0]) if A < 0.5: print _("[A] Power consumption is Nominal : {0}A < 500mA" ).format(A) else: print _( "CRITICAL: Power consumption Anomaly : {0}A, expected < 500mA" ).format(A) RETR = 1 except: print _("No response for M753") RETR = 1 else: print _("No response for M753") RETR = 1 # Result exit(RETR)
def test_case(): from fabtotum.utils.pyro.gcodeclient import GCodeServiceClient from fabtotum.fabui.config import ConfigService from selftests_common import getEndstopValues, getFrontPanelStatus # Pyro GCodeService wrapper gcs = GCodeServiceClient() config = ConfigService() try: safety_door = config.get('settings', 'safety.door') except KeyError: safety_door = 0 try: switch = config.get('settings', 'switch') except KeyError: switch = 0 try: bed_enabled = config.get('settings', 'hardware')['bed']['enable'] except KeyError: bed_enabled = True #################################################################### # Success RETR = 0 #~ print "Checking safety measures..." if safety_door == 1: if not getFrontPanelStatus(gcs): print _( "! Front panel door is opened, please close it or disable door safety." ) gcs.send('M18') exit(1) endstops_start = getEndstopValues(gcs) if switch == 0: # x_min endstop if not endstops_start['x_min'] or not endstops_start['y_max']: print _( "Move the head to front-left corner so that it triggeres the endstops" ) #~ print " Note: if you have done this and still get this error message, it could be the x_min is damaged" gcs.send('M18') exit(1) else: if not endstops_start['x_max'] or not endstops_start['y_max']: print _( "Move the head to front-right corner so that it triggeres the endstops" ) gcs.send('M18') exit(1) gcs.send('G27') ## check X endstops # Home all axis without probe endstops_after_g27 = getEndstopValues(gcs) if switch == 0: if endstops_start['x_min'] and not endstops_after_g27['x_min']: print _("x_min endstop: PASSED") else: print _("x_min endstop: FAILED") gcs.send('M18') exit(1) else: if endstops_start['x_max'] and not endstops_after_g27['x_max']: print _("x_max endstop: PASSED") else: print _("x_max endstop: FAILED") gcs.send('M18') exit(1) if endstops_start['y_max'] and not endstops_after_g27['y_max']: print _("y_max endstop: PASSED") else: print _("x_max endstop: FAILED") gcs.send('M18') exit(1) ## check Z endstop # move the platform up gcs.send('G91') gcs.send('G0 Z-10.00 F1000.00') gcs.send('M400') endstops_tmp = getEndstopValues(gcs) if not endstops_tmp['z_max'] and endstops_after_g27['z_max']: print _("z_max endstop: PASSED") else: print _("z_max endstop: FAILED") gcs.send('M18') exit(1) # If x_min is used for homing then check x_max if switch == 0: reply = gcs.send('M734') endstop_warning = reply[0] # Disable endstop warning reply = gcs.send('M734 S0') # Move head to x_max position gcs.send('G90') gcs.send('G0 X234.00 F1000.00') gcs.send('M400') endstops_tmp = getEndstopValues(gcs) # Move away from the endstop gcs.send('G91') gcs.send('G0 X-10 F1000.00') gcs.send('M400') # Restore enable endstop warning reply = gcs.send('M734 S{0}'.format(endstop_warning)) if not endstops_start['x_max'] and endstops_tmp['x_max']: print _("x_max endstop: PASSED") else: print _("x_max endstop: FAILED") gcs.send('M18') exit(1) ## Check y_min endstop reply = gcs.send('M734') endstop_warning = reply[0] # Disable endstop warning reply = gcs.send('M734 S0') # Move head to y_min position gcs.send('G90') gcs.send('G0 Y245.0 F1000.00') gcs.send('M400') endstops_tmp = getEndstopValues(gcs) # Move away from the endstop gcs.send('G91') gcs.send('G0 Y-10 F1000.00') gcs.send('M400') # Restore enable endstop warning reply = gcs.send('M734 S{0}'.format(endstop_warning)) if not endstops_start['y_min'] and endstops_tmp['y_min']: print _("y_min endstop: PASSED") else: print _("y_min endstop: FAILED") gcs.send('M18') exit(1) # Result exit(RETR)
class GCodePusher(object): """ GCode pusher. """ TASK_PREPARING = 'preparing' TASK_RUNNING = 'running' TASK_PAUSED = 'paused' TASK_COMPLETED = 'completed' TASK_COMPLETING = 'completing' TASK_ABORTING = 'aborting' TASK_ABORTED = 'aborted' TASK_TERMINATED = 'terminated' TYPE_PRINT = 'print' TYPE_MILL = 'mill' TYPE_SCAN = 'scan' TYPE_LASER = 'laser' UPDATE_PERIOD = 2 # seconds def __init__(self, log_trace=None, monitor_file=None, gcs=None, config=None, use_callback=True, use_stdout=False, update_period=2, lang='en_US.UTF-8', send_email=False, auto_shutdown=False): self.monitor_lock = RLock() self.UPDATE_PERIOD = update_period self.gcode_info = None self.lang = lang _ = setLanguage(self.lang) self.use_stdout = use_stdout # Task specific attributes self.task_stats = { 'type': 'unknown', 'controller': 'unknown', 'id': 0, 'pid': os.getpid(), 'status': GCodePusher.TASK_PREPARING, 'started_time': time.time(), 'estimated_time': 0, 'completed_time': 0, 'duration': 0, 'percent': 0.0, 'auto_shutdown': auto_shutdown, 'send_email': send_email, 'message': '' } # Pusher/File specific attributes self.pusher_stats = { 'file': { 'full_path': '', 'name': '', }, 'line_total': 0, 'line_current': 0, 'type': GCodeInfo.RAW, 'first_move': False } # Pusher/File specific attributes self.override_stats = { 'z_override': 0.0, 'fan': 0, 'rpm': 0, 'laser': 0, 'flow_rate': 0, 'speed': 0 } self.standardized_stats = { 'task': self.task_stats, 'gpusher': self.pusher_stats, 'override': self.override_stats } if not config: self.config = ConfigService() else: self.config = config if not gcs: self.gcs = GCodeServiceClient() else: self.gcs = gcs if not monitor_file: monitor_file = self.config.get('general', 'task_monitor') if not log_trace: log_trace = self.config.get('general', 'trace') self.monitor_file = monitor_file self.trace_file = log_trace self.trace_logger = logging.getLogger('Trace') self.trace_logger.setLevel(logging.INFO) ch = logging.FileHandler(log_trace) formatter = logging.Formatter("%(message)s") ch.setFormatter(formatter) ch.setLevel(logging.INFO) self.trace_logger.addHandler(ch) self.temperatres_file = self.config.get('general', 'temperature') if use_callback: self.gcs.register_callback(self.callback_handler) self.gmacro = GMacroHandler(self.gcs, self.config, self.trace, self.resetTrace, lang=self.lang) self.progress_monitor = None self.db = Database(self.config) def __send_task_email(self): if not self.task_stats["send_email"]: return import shlex, subprocess cmd = 'sudo -u www-data php /usr/share/fabui/index.php Std sendTaskEmail/{0}'.format( self.task_stats['id']) try: output = subprocess.check_output(shlex.split(cmd)) self.trace(_("Email sent")) except subprocess.CalledProcessError as e: self.trace(_("Email sending failed")) def __self_destruct(self): import signal print 'Initiating SIGKILL' pid = os.getpid() os.kill(pid, signal.SIGKILL) print 'SIGKILL Failed' def add_monitor_group(self, group, content={}): """ Add a custom group to monitor file with a specific content. If not content is provided, the groups is initialized with an empty dict. :param group: Group name. :param content: Dictinary containg group attributes. :type group: string :type content: dict """ if group not in self.standardized_stats: self.standardized_stats[group] = content return self.standardized_stats[group] def remove_monitor_group(self, group): """ Remove a custom group from the monitor file. :param group: Group name. :type group: string """ if group not in ['task', 'override', 'gpusher']: del self.standardized_stats[group] def update_monitor_file(self): """ Write stats to monitor file """ # Update duration self.task_stats['duration'] = str( time.time() - float(self.task_stats['started_time'])) if self.monitor_file: with open(self.monitor_file, 'w+') as file: file.write(json.dumps(self.standardized_stats)) def trace(self, log_msg): """ Write to log message to trace file :param log_msg: Log message :type log_msg: string """ if self.use_stdout: print log_msg else: self.trace_logger.info(log_msg) def resetTrace(self): """ Reset trace file """ #with open(self.trace_file, 'w'): # pass open(self.trace_file, 'w').close() def __shutdown_procedure(self): self.trace(_("Schutting down...")) # Wait for all commands to be finished reply = self.gcs.send('M400') # Tell totumduino Raspberry is going to sleep :'( reply = self.gcs.send('M729') # Stop the GCodeService connection self.gcs.stop() os.system('poweroff') def first_move_callback(self): self.trace(_("Task Started")) def __first_move_callback(self): """ Triggered when first move command in file executed """ self.pusher_stats['first_move'] = True self.first_move_callback() def gcode_comment_callback(self, data): """ Triggered when a comment in gcode file is detected """ pass def __gcode_comment_callback(self, data): if 'layer' in data: with self.monitor_lock: if 'print' in self.standardized_stats: self.standardized_stats['print']['layer_current'] = data[ 'layer'] self.update_monitor_file() self.gcode_comment_callback(data) def temp_change_callback(self, action, data): """ Triggered when temperature change is detected """ pass def __temp_change_callback(self, action, data): self.temp_change_callback(action, data) def gcode_action_callback(self, action, data): """ Triggered when action hook for a gcode command is activated """ pass def __gcode_action_callback(self, action, data): monitor_write = False with self.monitor_lock: if action == 'heating': if data[0] == 'M109': self.trace( _("Wait for nozzle temperature to reach {0}°C"). format(data[1])) elif data[0] == 'M190': self.trace( _("Wait for bed temperature to reach {0}°C"). format(data[1])) elif data[0] == 'M104': self.trace( _("Nozzle temperature set to {0}°C").format( data[1])) elif data[0] == 'M140': self.trace( _("Bed temperature set to {0}°C").format(data[1])) elif action == 'cooling': if data[0] == 'M106': if (len(data) > 1): s_value = data[1] else: s_value = FAN_MAX_VALUE value = int((float(s_value) / FAN_MAX_VALUE) * 100) self.trace(_("Fan value set to {0}%").format(value)) self.override_stats['fan'] = float(s_value) monitor_write = True elif data[0] == 'M107': self.trace(_("Fan off")) self.override_stats['fan'] = 0.0 monitor_write = True elif action == 'z_override': self.override_stats['z_override'] = float(data[0]) elif action == 'printing': if data[0] == 'M220': # Speed factor value = float(data[1]) self.trace(_("Speed factor set to {0}%").format(value)) self.override_stats['speed'] = float(data[1]) monitor_write = True elif data[0] == 'M221': # Extruder flow value = float(data[1]) self.trace(_("Extruder flow set to {0}%").format(value)) self.override_stats['flow_rate'] = float(data[1]) monitor_write = True elif action == 'milling': if data[0] == 'M0': """ .. todo: do something with it """ pass elif data[0] == 'M1': """ .. todo: do something with it """ pass elif data[0] == 'M3': value = int(data[1]) self.trace(_("Milling motor RPM set to {0}").format(value)) self.override_stats['rpm'] = float(data[1]) monitor_write = True elif data[0] == 'M4': value = int(data[1]) self.trace(_("Milling motor RPM set to {0}").format(value)) self.override_stats['rpm'] = float(data[1]) monitor_write = True elif data[0] == 'M6': value = float(data[1]) """ .. todo: Check whether laser power should be scaled from 0-255 to 0.0-100.0 """ self.trace(_("Laser power set to {0}%").format(value)) self.override_stats['laser'] = float(data[1]) monitor_write = True elif action == 'pause': self.pause() elif action == 'message': self.task_stats['message'] = data self.trace(data) if monitor_write: self.update_monitor_file() self.gcode_action_callback(action, data) def file_done_callback(self): """ Triggered when gcode file execution is completed """ if self.task_stats["auto_shutdown"]: self.__shutdown_procedure() else: self._stop() def __file_done_callback(self, data): """ Internal file done callback preventing user from overloading it. """ with self.monitor_lock: self.task_stats['percent'] = 100.0 self.update_monitor_file() self.file_done_callback() if self.task_stats['status'] == self.TASK_COMPLETED: self.__send_task_email() def finish_task(self): self.gcs.finish() def set_task_status(self, status): """ Set task status. :param status: Can be one of `GCodePusher.TASK_*` values """ with self.monitor_lock: self.task_stats['status'] = status self.update_monitor_file() if (status == GCodePusher.TASK_COMPLETED or status == GCodePusher.TASK_ABORTED): self.task_stats['completed_time'] = time.time() self.__update_task_db() if (status == GCodePusher.TASK_COMPLETED or status == GCodePusher.TASK_COMPLETING or status == GCodePusher.TASK_ABORTING or status == GCodePusher.TASK_ABORTED or status == GCodePusher.TASK_RUNNING): self.__update_task_db() def is_aborted(self): return (self.task_stats['status'] == GCodePusher.TASK_ABORTED or self.task_stats['status'] == GCodePusher.TASK_ABORTING) def is_paused(self): return self.task_stats['status'] == GCodePusher.TASK_PAUSED def is_started(self): return self.task_stats['status'] == GCodePusher.TASK_RUNNING def is_completed(self): return (self.task_stats['status'] == GCodePusher.TASK_COMPLETED or self.task_stats['status'] == GCodePusher.TASK_COMPLETING) def state_change_callback(self, data): """ Triggered when state is changed. (paused/resumed) """ pass def __state_change_callback(self, data): """ """ with self.monitor_lock: if data == 'paused': #~ self.trace( _("Task has been paused") ) self.task_stats['status'] = GCodePusher.TASK_PAUSED #self.monitor_info["paused"] = True elif data == 'resumed': self.task_stats['status'] = GCodePusher.TASK_RUNNING elif data == 'aborted': #~ self.trace( _("Task has been aborted") ) self.task_stats['status'] = GCodePusher.TASK_ABORTING self.__update_task_db() elif data == 'terminated': self.trace(_("Task has been terminated")) self.task_stats['status'] = GCodePusher.TASK_TERMINATED self.update_monitor_file() self.__self_destruct() self.update_monitor_file() self.state_change_callback(data) with self.monitor_lock: if data == 'resuming': self.gcs.resumed() def progress_callback(self, percentage): """ Triggered when progress percentage changes :param percentage: Progress percentage 0.0 to 100.0 :type percentage: float """ pass def error_callback(self, error_no): """ Triggered when an error occures. :param error_no: Error number :param error_msg: Error message :type error_no: int :type error_msg: string """ pass def __error_callback(self, error_no): # TODO: process errors # TODO: complete ERROR_MESSAGE self.error_callback(error_no) def __config_change_callback(self, id, data): if id == 'shutdown': with self.monitor_lock: self.task_stats["auto_shutdown"] = (data == 'on') self.update_monitor_file() elif id == 'email': with self.monitor_lock: self.task_stats["send_email"] = (data == 'on') self.update_monitor_file() elif id == 'reload': self.config.reload() def callback_handler(self, action, data): if action == 'file_done': self.__file_done_callback(data) elif action == 'gcode_comment': self.__gcode_comment_callback(data) elif action.startswith('gcode_action'): self.__gcode_action_callback(action.split(':')[1], data) elif action == 'first_move': self.__first_move_callback() elif action.startswith('temp_change'): self.__temp_change_callback(action.split(':')[1], data) elif action == 'state_change': self.__state_change_callback(data) elif action.startswith('config:'): self.__config_change_callback(action.split(':')[1], data) elif action == 'error': self.__error_callback(data[0]) elif action == 'self_descruct': print 'Self Descruct sequence activated...' self.__self_destruct() else: self.custom_action_callback(action, data) def custom_action_callback(self, action, data): """ Handle user defined action """ pass def get_progress(self): """ Get progress of file push or override this function for custom progress calculation. """ return self.gcs.get_progress() def __progress_monitor_thread(self): old_progress = -1 monitor_write = False while self.gcs.still_running(): progress = self.get_progress() if old_progress != progress: old_progress = progress dur = float(self.task_stats['duration']) first_move = self.pusher_stats['first_move'] if progress == 0.0 or first_move == False: self.task_stats['estimated_time'] = 0 else: self.task_stats['estimated_time'] = ( (dur / float(progress)) * 100.0) print self.task_stats['estimated_time'], progress self.progress_callback(progress) # Write progress even if it did not change because duration is update # during update_monitor_file() with self.monitor_lock: self.task_stats['percent'] = progress self.update_monitor_file() time.sleep(GCodePusher.UPDATE_PERIOD) def prepare_task(self, task_id, task_type='unknown', task_controller='make', gcode_file=None): self.task_stats['type'] = task_type self.task_stats['controller'] = task_controller self.task_stats['id'] = task_id self.task_stats['status'] = GCodePusher.TASK_PREPARING self.task_stats['started_time'] = time.time() self.task_stats['completed_time'] = 0 self.task_stats['estimated_time'] = 0 self.task_stats['duration'] = 0 self.task_stats['percent'] = 0.0 #~ self.task_stats['auto_shutdown'] = auto_shutdown # configured in __init __ #~ self.task_stats['send_email'] = send_email # configured in __init __ self.task_stats['message'] = '' self.override_stats['z_override'] = 0.0 self.override_stats['fan'] = 0 self.override_stats['rpm'] = 0 self.override_stats['laser'] = 0 self.override_stats['flow_rate'] = 100.0 self.override_stats['speed'] = 100.0 self.resetTrace() if gcode_file: self.trace(_("Processing file")) self.trace(_("This may take a while, please wait")) gfile = GCodeFile(gcode_file) self.trace(_("File processed")) task_db = self.get_task(task_id) file = self.get_file(task_db['id_file']) self.pusher_stats['file']['full_path'] = gcode_file self.pusher_stats['file']['name'] = file['client_name'] self.pusher_stats['line_total'] = gfile.info['line_count'] self.pusher_stats['line_current'] = 0 self.pusher_stats['type'] = gfile.info['type'] self.pusher_stats['first_move'] = False if gfile.info['type'] == GCodeInfo.PRINT: engine = 'unknown' if 'slicer' in gfile.info: engine = gfile.info['slicer'] layer_total = 0 if 'layer_count' in gfile.info: layer_total = int(gfile.info['layer_count']) if 'print' not in self.standardized_stats: self.print_stats = { 'layer_total': layer_total, 'layer_current': 0, 'engine': engine } self.add_monitor_group('print', self.print_stats) else: self.standardized_stats['print']['engine'] = engine self.standardized_stats['print']['layer_current'] = 0 self.standardized_stats['print'][ 'layer_total'] = layer_total elif gfile.info['type'] == GCodeInfo.MILL or gfile.info[ 'type'] == GCodeInfo.DRILL: self.mill_stats = { # Place holder } self.add_monitor_group('mill', self.mill_stats) #~ elif gfile.info['type'] == GCodeInfo.LASER: #~ self.laser_stats = { #~ # Place holder #~ } #~ self.add_monitor_group('laser', self.laser_stats) if self.monitor_file: self.progress_monitor = Thread( target=self.__progress_monitor_thread) self.progress_monitor.start() with self.monitor_lock: self.update_monitor_file() def __update_task_db(self): """ Converts task_stats to compatible format for sys_tasks table and writes the values to the database. """ task_id = self.task_stats['id'] if task_id == 0: return task_db = Task(self.db, task_id) if (self.task_stats['status'] == GCodePusher.TASK_PREPARING or self.task_stats['status'] == GCodePusher.TASK_RUNNING or self.task_stats['status'] == GCodePusher.TASK_PAUSED): task_db['status'] = GCodePusher.TASK_RUNNING elif (self.task_stats['status'] == GCodePusher.TASK_COMPLETED or self.task_stats['status'] == GCodePusher.TASK_ABORTING or self.task_stats['status'] == GCodePusher.TASK_ABORTED): task_db['status'] = self.task_stats['status'] task_db['finish_date'] = timestamp2datetime( self.task_stats['completed_time']) task_db['type'] = self.task_stats['type'] task_db['controller'] = self.task_stats['controller'] tid = task_db.write() if task_id == TableItem.DEFAULT: self.task_stats['id'] = tid with self.monitor_lock: self.update_monitor_file() def loop(self): """ Wait for all GCodePusher threads to finish. """ self.gcs.loop() if self.progress_monitor: self.progress_monitor.join() time.sleep(0.5) def __stop_thread(self): self.gcs.stop() def stop(self): """ Signal all GCodePusher threads to stop. """ stop_thread = Thread(target=self.__stop_thread) stop_thread.start() def exec_macro(self, preset, args=None, atomic=True): """ Execute macro command. """ return self.gmacro.run(preset, args, atomic, reset_trace=False) def send(self, code, block=True, timeout=None, trace=None, group='gcode', expected_reply='ok'): """ Send a single gcode command and display trace message. """ if trace: self.trace(trace) #TODO: ConnectionClosedError return self.gcs.send(code, block=block, timeout=timeout, group=group, expected_reply=expected_reply) def send_file(self, filename): """ Send a file to totumduino. File will be send line by line and it's progress can be monitored using `get_progress` function. When the file has been completely sent `file_done_callback` will be called. """ return self.gcs.send_file(filename) def get_temperature_history(self): """ Return temperature history data. """ try: json_f = open(self.temperatres_file, 'r') return json.load(json_f) except: return {} #### Object related API #### def get_task(self, task_id): t = Task(self.db, task_id) if t.exists(): return t return None def get_file(self, file_id): f = File(self.db, file_id) if f.exists(): return f return None def get_object(self, object_id): obj = Object(self.db, object_id) if obj.exists(): return obj return None def add_object(self, name, desc, user_id, public=Object.PUBLIC): """ Add object to database. """ obj = Object(self.db, user_id=user_id, name=name, desc=desc, public=public) obj.write() return obj def delete_object(self, object_id): """ Remove object from database and all the files associated to it. """ to_delete = [] obj = self.get_object(object_id) if obj: ofmap = ObjFile(self.db) files = ofmap.object_files(object_id) for fid in files: f = File(self.db, file_id=fid) aids = ofmap.file_associations(fid) # Check if file is only associated to one object # if so we can remove it from db and filesystem if len(aids) == 1: to_delete.append(f['full_path']) f.delete() # Remove all associations with object_id aids = ofmap.object_associations(object_id) ofmap.delete(aids) obj.delete() for f in to_delete: try: os.remove(f) except Exception as e: pass def pause(self): self.gcs.pause() def resume(self): self.gcs.resume()
class GCodePusher(object): """ GCode pusher. """ def __init__(self, log_trace, monitor_file = None, gcs = None, use_callback = True): self.config = ConfigService() self.monitor_file = monitor_file self.trace_file = log_trace self.monitor_lock = RLock() self.monitor_info = { "progress" : 0.0, "paused" : False, "print_started" : False, "started" : time.time(), "auto_shutdown" : False, "completed" : False, "completed_time" : 0, "layer_count" : 0, "current_layer" : 0, "filename" : "", "task_id" : 0, "ext_temp" : 0.0, "ext_temp_target" : 0.0, "bed_temp" : 0.0, "bed_temp_target" : 0.0, "z_override" : 0.0, "rpm" : 0.0, "laser" : 0.0, "fan" : 0.0, "speed" : 100.0, "flow_rate" : 100.0, "tip" : False, "message" : '', "current_line_number" : 0, "gcode_info" : None } if not gcs: self.gcs = GCodeServiceClient() else: self.gcs = gcs if use_callback: self.gcs.register_callback(self.callback_handler) self.macro_error = 0 self.macro_warning = 0 self.macro_skipped = 0 self.progress_monitor = None logging.basicConfig( filename=log_trace, level=logging.INFO, format='%(message)s') def writeMonitor(self): """ Write stats to monitor file """ _layers = { 'total' : str(self.monitor_info['layer_count']), 'actual': str(self.monitor_info['current_layer']) } _stats = { "percent" : str(self.monitor_info['progress']), "line_number" : str(self.monitor_info['current_line_number']), "extruder" : str(self.monitor_info['ext_temp']), "bed" : str(self.monitor_info['bed_temp']), "extruder_target" : str(self.monitor_info['ext_temp_target']), "bed_target" : str(self.monitor_info['bed_temp_target'] ), "z_override" : str(self.monitor_info['z_override']), "layers" : str(self.monitor_info['layer_count']), "rpm" : str(self.monitor_info['rpm']), "fan" : str(self.monitor_info['fan']), "speed" : str(self.monitor_info['speed']), "flow_rate" : str(self.monitor_info['flow_rate']) } _tip = { "show" : str(self.monitor_info['tip']), "message" : str(self.monitor_info['message']) } if self.monitor_info["gcode_info"]: filename = self.monitor_info["gcode_info"]["filename"] line_count = self.monitor_info["gcode_info"]["line_count"] else: filename ='' line_count = 0 _print = { "name" : str(filename), "lines" : str(line_count), "print_started" : str(self.monitor_info["print_started"]), "started" : str(self.monitor_info["started"]), "paused" : str(self.monitor_info["paused"]), "completed" : str(self.monitor_info["completed"]), "completed_time" : str(self.monitor_info["completed_time"]), "shutdown" : str(self.monitor_info["auto_shutdown"]), "tip" : _tip, "stats" : _stats } engine = 'unknown' if self.monitor_info["gcode_info"]: if 'slicer' in self.monitor_info["gcode_info"]: engine = self.monitor_info["gcode_info"]["slicer"] stats = { "type" : "print", "print" : _print, "engine" : str(engine), "task_id" : self.monitor_info["task_id"] } if self.monitor_file: with open(self.monitor_file,'w+') as file: file.write(json.dumps(stats)) def trace(self, log_msg): """ Write to log message to trace file :param log_msg: Log message :type log_msg: string """ logging.info(log_msg) def resetTrace(self): """ Reset trace file """ with open(self.trace_file, 'w'): pass def __shutdown_procedure(self): self.trace( _("Schutting down...") ) # Wait for all commands to be finished reply = self.gcs.send('M400') # Tell totumduino Raspberry is going to sleep :'( reply = self.gcs.send('M729') # Stop the GCodeService connection self.gcs.stop() # TODO: trigger system shutdown def first_move_callback(self): self.trace( _("Task Started") ) def __first_move_callback(self): """ Triggered when first move command in file executed """ self.monitor_lock.acquire() self.monitor_info['print_started'] = True self.monitor_lock.release() self.first_move_callback() def gcode_comment_callback(self, data): """ Triggered when a comment in gcode file is detected """ pass def __gcode_comment_callback(self, data): self.monitor_lock.acquire() if 'layer' in data: self.monitor_info['current_layer'] = data['layer'] self.monitor_lock.release() self.gcode_comment_callback(data) def temp_change_callback(self, action, data): """ Triggered when temperature change is detected """ pass def __temp_change_callback(self, action, data): self.monitor_lock.acquire() if action == 'all': #print "Ext: {0}, Bed: {1}".format(data[0], data[1]) self.monitor_info['ext_temp'] = float(data[0]) self.monitor_info['bed_temp'] = float(data[1]) elif action == 'bed': #print "Bed: {0}".format(data[0]) self.monitor_info['bed_temp'] = float(data[0]) elif action == 'ext': #print "Ext: {0}".format(data[0]) self.monitor_info['ext_temp'] = float(data[0]) self.monitor_lock.release() self.writeMonitor() self.temp_change_callback(action, data) def gcode_action_callback(self, action, data): """ Triggered when action hook for a gcode command is activated """ pass def __gcode_action_callback(self, action, data): monitor_write = False self.monitor_lock.acquire() if action == 'heating': if data[0] == 'M109': self.trace( _("Wait for nozzle temperature to reach {0}°C").format(data[1]) ) self.monitor_info['ext_temp_target'] = float(data[1]) monitor_write = True elif data[0] == 'M190': self.trace( _("Wait for bed temperature to reach {0}°C").format(data[1]) ) self.monitor_info['bed_temp_target'] = float(data[1]) monitor_write = True elif data[0] == 'M104': self.trace( _("Nozzle temperature set to {0}°C").format(data[1]) ) self.monitor_info['ext_temp_target'] = float(data[1]) monitor_write = True elif data[0] == 'M140': self.trace( _("Bed temperature set to {0}°C").format(data[1]) ) self.monitor_info['bed_temp_target'] = float(data[1]) monitor_write = True elif action == 'cooling': if data[0] == 'M106': value = int((float( data[1] ) / 255) * 100) self.trace( _("Fan value set to {0}%").format(value) ) self.monitor_info['fan'] = float(data[1]) monitor_write = True elif data[0] == 'M107': self.trace( _("Fan off") ) self.monitor_info['fan'] = 0.0 monitor_write = True elif action == 'printing': if data[0] == 'M220': # Speed factor value = float( data[1] ) self.trace( _("Speed factor set to {0}%").format(value) ) self.monitor_info['speed'] = float(data[1]) monitor_write = True elif data[0] == 'M221': # Extruder flow value = float( data[1] ) self.trace( _("Extruder flow set to {0}%").format(value) ) self.monitor_info['flow_rate'] = float(data[1]) monitor_write = True elif action == 'milling': if data[0] == 'M0': """ .. todo: do something with it """ pass elif data[0] == 'M1': """ .. todo: do something with it """ pass elif data[0] == 'M3': self.trace( _("Milling motor RPM set to {0}%").format(value) ) self.monitor_info['rpm'] = float(data[1]) monitor_write = True elif data[0] == 'M4': self.trace( _("Milling motor RPM set to {0}%").format(value) ) self.monitor_info['rpm'] = float(data[1]) monitor_write = True elif data[0] == 'M6': """ .. todo: Check whether laser power should be scaled from 0-255 to 0.0-100.0 """ self.trace( _("Laser power set to {0}%").format(value) ) self.monitor_info['laser'] = float(data[1]) monitor_write = True elif action == 'message': print "MSG: {0}".format(data) self.monitor_lock.release() if monitor_write: self.writeMonitor() self.gcode_action_callback(action, data) def file_done_callback(self): """ Triggered when gcode file execution is completed """ if self.monitor_info["auto_shutdown"]: self.__shutdown_procedure() else: self._stop() def __file_done_callback(self, data): """ Internal file done callback preventing user from overloading it. """ self.monitor_lock.acquire() self.monitor_info["completed_time"] = int(time.time()) self.monitor_info["completed"] = True self.monitor_info['progress'] = 100.0 #gcs.get_progress() self.writeMonitor() self.monitor_lock.release() self.file_done_callback() def state_change_callback(self, data): """ Triggered when state is changed. (paused/resumed) """ pass def __state_change_callback(self, data): self.monitor_lock.acquire() if data == 'paused': self.trace( _("Print is now paused") ) self.monitor_info["paused"] = True elif data == 'resumed': self.monitor_info["paused"] = False self.monitor_lock.release() self.writeMonitor() self.state_change_callback(data) def progress_callback(self, percentage): """ Triggered when progress percentage changes :param percentage: Progress percentage 0.0 to 100.0 :type percentage: float """ pass def error_callback(self, error_no, error_msg): """ Triggered when an error occures. :param error_no: Error number :param error_msg: Error message :type error_no: int :type error_msg: string """ pass def __error_callback(self, error_no, error_msg): # TODO: process errors # TODO: complete ERROR_MESSAGE self.error_callback(error_no, error_msg) def callback_handler(self, action, data): if action == 'file_done': self.__file_done_callback(data) elif action == 'gcode_comment': self.__gcode_comment_callback(data) elif action.startswith('gcode_action'): self.__gcode_action_callback(action.split(':')[1], data) elif action == 'first_move': self.__first_move_callback() elif action.startswith('temp_change'): self.__temp_change_callback(action.split(':')[1], data) elif action == 'state_change': self.__state_change_callback() elif action == 'error': self.__error_callback(data[0], data[1]) def progress_monitor_thread(self): old_progress = -1 monitor_write = False while self.gcs.still_running(): progress = self.gcs.get_progress() if self.monitor_info["gcode_info"]: if self.monitor_info["gcode_info"]["type"] == GCodeInfo.PRINT: reply = self.gcs.send("M105") self.monitor_lock.acquire() try: a, b, c, d = parse_temperature(reply[0]) self.monitor_info['ext_temp'] = a self.monitor_info['ext_temp_target'] = b self.monitor_info['bed_temp'] = c self.monitor_info['bed_temp_target'] = d except Exception: pass self.monitor_lock.release() monitor_write = True if old_progress != progress: old_progress = progress self.monitor_lock.acquire() self.monitor_info['progress'] = progress self.monitor_lock.release() self.progress_callback(progress) monitor_write = True if monitor_write: self.writeMonitor() monitor_write = False time.sleep(2) def prepare(self, gcode_file, task_id, ext_temp_target = 0.0, bed_temp_target = 0.0, rpm = 0): """ :param gcode_file: :param task_id: :param ext_temp_target: :param bed_temp_target: :param rpm: ??? """ gfile = GCodeFile(gcode_file) self.monitor_info["progress"] = 0.0 self.monitor_info["paused"] = False self.monitor_info["print_started"] = False self.monitor_info["started"] = time.time() self.monitor_info["auto_shutdown"] = False self.monitor_info["completed"] = False self.monitor_info["completed_time"] = 0 self.monitor_info["layer_count" ] = 0 self.monitor_info["current_layer"] = 0 self.monitor_info["filename"] = gcode_file self.monitor_info["task_id"] = task_id #self.monitor_info["ext_temp"] = ext_temp self.monitor_info["ext_temp_target"] = ext_temp_target #self.monitor_info["bed_temp"] = bed_temp self.monitor_info["bed_temp_target"] = bed_temp_target self.monitor_info["z_override"] = 0.0 self.monitor_info["rpm"] = 0 self.monitor_info["fan"] = 0.0 self.monitor_info["speed"] = 100.0 self.monitor_info["flow_rate"] = 100.0 self.monitor_info["tip"] = False self.monitor_info["message"] = '' self.monitor_info["current_line_number"] = 0 self.monitor_info["gcode_info"] = gfile.info if self.monitor_file: print "Creating monitor thread" self.progress_monitor = Thread( target=self.progress_monitor_thread ) self.progress_monitor.start() else: print "Skipping monitor thread" if gfile.info['type'] == GCodeInfo.PRINT: # READ TEMPERATURES BEFORE PRINT STARTS (improve UI feedback response) reply = self.gcs.send("M105") if reply: ext_temp, ext_temp_target, bed_temp, bed_temp_target = parse_temperature(reply[0]) self.monitor_info["ext_temp"] = ext_temp self.monitor_info["ext_temp_target"] = ext_temp_target self.monitor_info["bed_temp"] = bed_temp self.monitor_info["bed_temp_target"] = bed_temp_target self.monitor_info["z_override"] = 0.0 self.monitor_info["rpm"] = rpm self.resetTrace() def loop(self): """ Wait for all GCodePusher threads to finish. """ self.gcs.loop() if self.progress_monitor: self.progress_monitor.join() time.sleep(0.5) def __stop_thread(self): self.gcs.stop() def stop(self): """ Signal all GCodePusher threads to stop. """ stop_thread = Thread( target = self.__stop_thread ) stop_thread.start() def reset_macro_status(self): """ Reset macro status counters to zero. """ self.macro_warning = 0 self.macro_error = 0 self.macro_skipped = 0 def macro_start(self): pass # self.atomic_begin() def macro_end(self): pass # self.atomic_end() def macro(self, code, expected_reply, timeout, error_msg, delay_after, warning=False, verbose=True): """ Send a command and check it's reply. :param code: gcode :param expected_reply: Expected reply :param error_msg: Error message to display :param timeout: Reply timeout in seconds :param delay_after: Time in seconds to wait after receiving the rely :param warning: Treat wrong reply as warning not as error :param verbose: Whether initial message should be displayed or not. :type code: string :type expected_reply: string :type timeout: float :type error_msg: string :type delay_after: float :type warning: bool :type verbose: bool """ if self.macro_error == 0: if verbose: self.trace(error_msg) reply = self.gcs.send(code, timeout=timeout, group = 'macro') if expected_reply: # Check if the reply is as expected if reply[0] != expected_reply: if warning: self.trace(error_msg + _(": Warning!")) self.macro_warning += 1 else: self.trace(error_msg + _(": Failed ({0})".format(reply[0]) )) self.macro_error += 1 else: self.trace(error_msg + _(": Skipped")) self.macro_skipped += 1 #time.sleep(delay_after) #wait the desired amount def send(self, code, block = True, timeout = None, trace = None): """ Send a single gcode command and display trace message. """ if trace: self.trace(trace) return self.gcs.send(code, expected_reply, block, timeout) def send_file(self, filename): """ """ return self.gcs.send_file(filename)
def main(): config = ConfigService() gcs = GCodeServiceClient() data = {} # Memory with open('/proc/meminfo', 'r') as f: meminfo = f.read().split() data['mem_total'] = int(meminfo[1]) data['mem_free'] = int(meminfo[4]) data['mem_used_percentage'] = int( (data['mem_free'] * 100.0) / data['mem_total']) # Board Temperature with open('/sys/class/thermal/thermal_zone0/temp', 'r') as f: tmp = float(f.read()) data['temp'] = tmp / 1000.0 # Uptime with open('/proc/uptime', 'r') as f: tmp = f.read().split() data['time_alive'] = round(float(tmp[0])) # BCM2709 RPi2/RPi3 # BCM2708 RPi1 # Raspberry Pi version #soc_id = shell_exec('</proc/cpuinfo grep Hardware | awk \'{print $3}\'')[0].strip() #name_id = '' #soc_name = {'BCM2708' : 'Raspberry Pi Model B', 'BCM2709' : 'Raspberry Pi 3 Model B' } #if soc_id in soc_name: # data['rpi_version'] = soc_name[soc_id] #else: # data['rpi_version'] = soc_id data['rpi_version'] = rpi_version() # Storage tmp = shell_exec('df -Ph') table_header = tmp[0].split()[:-1] table_rows = [] visible_partitions = [ '/tmp', '/mnt/bigtemp', '/mnt/userdata', '/mnt/live/mnt/changes', '/mnt/live/mnt/bundles', '/mnt/live/mnt/boot' ] for row in tmp[1:]: tmp2 = row.split() if tmp2[5] in visible_partitions: table_rows.append(" ".join(tmp2)) data['table_header'] = table_header data['table_rows'] = table_rows # OS Info data['os_info'] = shell_exec('uname -a')[0].strip() # Fabtotum info #reply = gcs.send('M765') #fw = reply[0].split()[1] #reply = gcs.send('M763') #hw = reply[0] #data['fabtotum_info'] = {'fw':fw, 'hw':hw} # FABUI version ##db = Database(config) #fabui_version = SysConfig(db) #fabui_version.query_by('key', 'fabui_version') #data['fabui_version'] = fabui_version['text'] data['unit_configs'] = config.settings network_json_info = open(config.get('general', 'network_info_file')) network_info = json.load(network_json_info) data['eth_bytes'] = get_rx_tx_bytes('eth0') if 'wlan0' in network_info['interfaces']: data['wlan_bytes'] = get_rx_tx_bytes('wlan0') print json.dumps(data)
#!/bin/env python # -*- coding: utf-8; -*- #from gcodeclient import GCodeServicePyroClient from fabtotum.utils.pyro.gcodeclient import GCodeServiceClient def callback_function(action, data): print "Callback working:", action if action == 'file_done': gcs.stop() else: print action, data gcs = GCodeServiceClient() #print gcs.send('M732') #print gcs.send('M734') #print gcs.send('M730') print gcs.send('M756 E102') #~ reply = gcs.send('M119') #~ print reply #~ data = gcs.send('M503') #data = "".join(data, "\n") #z_probe_old = float(data.split("Z Probe Length: ")[1].split("\n")[0])
def __init__(self, log_trace=None, monitor_file=None, gcs=None, config=None, use_callback=True, use_stdout=False, update_period=2, lang='en_US.UTF-8', send_email=False, auto_shutdown=False): self.monitor_lock = RLock() self.UPDATE_PERIOD = update_period self.gcode_info = None self.lang = lang _ = setLanguage(self.lang) self.use_stdout = use_stdout # Task specific attributes self.task_stats = { 'type': 'unknown', 'controller': 'unknown', 'id': 0, 'pid': os.getpid(), 'status': GCodePusher.TASK_PREPARING, 'started_time': time.time(), 'estimated_time': 0, 'completed_time': 0, 'duration': 0, 'percent': 0.0, 'auto_shutdown': auto_shutdown, 'send_email': send_email, 'message': '' } # Pusher/File specific attributes self.pusher_stats = { 'file': { 'full_path': '', 'name': '', }, 'line_total': 0, 'line_current': 0, 'type': GCodeInfo.RAW, 'first_move': False } # Pusher/File specific attributes self.override_stats = { 'z_override': 0.0, 'fan': 0, 'rpm': 0, 'laser': 0, 'flow_rate': 0, 'speed': 0 } self.standardized_stats = { 'task': self.task_stats, 'gpusher': self.pusher_stats, 'override': self.override_stats } if not config: self.config = ConfigService() else: self.config = config if not gcs: self.gcs = GCodeServiceClient() else: self.gcs = gcs if not monitor_file: monitor_file = self.config.get('general', 'task_monitor') if not log_trace: log_trace = self.config.get('general', 'trace') self.monitor_file = monitor_file self.trace_file = log_trace self.trace_logger = logging.getLogger('Trace') self.trace_logger.setLevel(logging.INFO) ch = logging.FileHandler(log_trace) formatter = logging.Formatter("%(message)s") ch.setFormatter(formatter) ch.setLevel(logging.INFO) self.trace_logger.addHandler(ch) self.temperatres_file = self.config.get('general', 'temperature') if use_callback: self.gcs.register_callback(self.callback_handler) self.gmacro = GMacroHandler(self.gcs, self.config, self.trace, self.resetTrace, lang=self.lang) self.progress_monitor = None self.db = Database(self.config)
def test_case(): from fabtotum.utils.pyro.gcodeclient import GCodeServiceClient from fabtotum.fabui.config import ConfigService from selftests_common import getEndstopValues, getFrontPanelStatus # Pyro GCodeService wrapper gcs = GCodeServiceClient() config = ConfigService() try: safety_door = config.get('settings', 'safety.door') except KeyError: safety_door = 0 try: switch = config.get('settings', 'switch') except KeyError: switch = 0 try: bed_enabled = config.get('settings', 'hardware')['bed']['enable'] except KeyError: bed_enabled = True #################################################################### # Success RETR = 0 #~ print "Checking safety measures..." if safety_door == 1: if not getFrontPanelStatus(gcs): print _( "! Front panel door is opened, please close it or disable door safety." ) gcs.send('M18') exit(1) gcs.send('G27') for i in [5, 7, 8, 10, 15, 18]: speed = int(1000 * i) print 'Speed F = {0} mm/sec'.format(round(speed / 60.0, 2)) gcs.send('G90') # Long streight movements gcs.send('G0 X3 Y3 F{0}'.format(speed)) gcs.send('G0 X3 Y232 F{0}'.format(speed)) gcs.send('G0 X212 Y232 F{0}'.format(speed)) gcs.send('G0 X212 Y3 F{0}'.format(speed)) gcs.send('G0 X3 Y3 F{0}'.format(speed)) # Long diagonal movements gcs.send('G0 X212 Y212 F{0}'.format(speed)) gcs.send('G0 X3 Y212 F{0}'.format(speed)) gcs.send('G0 X212 Y3 F{0}'.format(speed)) gcs.send('G0 X3 Y3 F{0}'.format(speed)) # Short zig-zag (square) movements gcs.send('G0 X50 Y3 F{0}'.format(speed)) gcs.send('G0 X50 Y20 F{0}'.format(speed)) gcs.send('G0 X100 Y20 F{0}'.format(speed)) gcs.send('G0 X100 Y40 F{0}'.format(speed)) gcs.send('G0 X50 Y40 F{0}'.format(speed)) gcs.send('G0 X50 Y60 F{0}'.format(speed)) gcs.send('G0 X100 Y60 F{0}'.format(speed)) gcs.send('G0 X100 Y80 F{0}'.format(speed)) gcs.send('G0 X50 Y80 F{0}'.format(speed)) gcs.send('G0 X50 Y100 F{0}'.format(speed)) gcs.send('G0 X100 Y100 F{0}'.format(speed)) gcs.send('G0 X100 Y120 F{0}'.format(speed)) gcs.send('G0 X50 Y120 F{0}'.format(speed)) gcs.send('G0 X50 Y140 F{0}'.format(speed)) gcs.send('G0 X100 Y140 F{0}'.format(speed)) gcs.send('G0 X100 Y160 F{0}'.format(speed)) gcs.send('G0 X50 Y160 F{0}'.format(speed)) gcs.send('G0 X50 Y180 F{0}'.format(speed)) gcs.send('G0 X100 Y180 F{0}'.format(speed)) gcs.send('G0 X100 Y200 F{0}'.format(speed)) gcs.send('G0 X3 Y3 F{0}'.format(speed)) # Result exit(RETR)