def activate_plugin(plugin, config=None, db=None): if not config: config = ConfigService() if not db: db = Database(config) plugins_path = config.get('general', 'plugins_path') fabui_path = config.get('general', 'fabui_path') plugin_dir = os.path.join(plugins_path, plugin) if not os.path.exists(plugin_dir): return False # Link controller create_link( os.path.join(plugin_dir, 'controller.php'), os.path.join(fabui_path, 'application/controllers/Plugin_{0}.php'.format(plugin) ) ) # Link views create_dir(os.path.join( fabui_path, 'application/views/plugin' ) ) create_link( os.path.join(plugin_dir, 'views'), os.path.join(fabui_path, 'application/views/plugin/{0}'.format(plugin)) ) # Link assets create_dir( os.path.join( fabui_path, 'assets/plugin' ) ) create_link( os.path.join(plugin_dir, 'assets'), os.path.join(fabui_path, 'assets/plugin/{0}'.format(plugin)) ) meta_file = os.path.join( plugin_dir, "meta.json" ) with open(meta_file) as f: meta_content = f.read() p = Plugin(db) p['name'] = plugin p['attributes'] = meta_content p.write() return True
class Translation(): def __init__(self, config=None): if not config: self.config = ConfigService() self.tr = gettext.translation('fabui', '/usr/share/fabui/locale', fallback=True) self.tp = gettext.translation('fabui', '/usr/share/fabui/locale', fallback=True) def setLanguage(self, lang, domain='fabui'): locale_path = self.config.get('general', 'locale_path') self.tr = gettext.translation('fabui', locale_path, fallback=True, languages=[lang]) def setPluginLanguage(self, plugin_name, lang): plugins_path = self.config.get('general', 'plugins_path') locale_path = '{0}{1}/locale'.format(plugins_path, plugin_name) self.tp = gettext.translation(plugin_name, locale_path, fallback=True, languages=[lang]) def get(self, text): t = self.tp.gettext(text) if t == text: t = self.tr.gettext(text) return t
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 main(): config = ConfigService() # SETTING EXPECTED ARGUMENTS parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument("-T", "--task-id", help="Task ID.", default=0) parser.add_argument("-F", "--file-name", help="File name.", required=True) parser.add_argument( "--autolevel", action='store_true', help="Auto bed leveling. Valid only when --standalone is used.", default=False) parser.add_argument("--lang", help="Output language", default='en_US.UTF-8') parser.add_argument("--email", help="Send an email on task finish", action='store_true', default=False) parser.add_argument("--shutdown", help="Shutdown on task finish", action='store_true', default=False) # GET ARGUMENTS args = parser.parse_args() # INIT VARs gcode_file = args.file_name # GCODE FILE task_id = args.task_id autolevel = args.autolevel lang = args.lang send_email = bool(args.email) if task_id == 0: standalone = True else: standalone = False monitor_file = config.get( 'general', 'task_monitor' ) # TASK MONITOR FILE (write stats & task info, es: temperatures, speed, etc log_trace = config.get('general', 'trace') # TASK TRACE FILE app = PrintApplication(log_trace, monitor_file, standalone, autolevel, lang=lang, send_email=send_email) app.run(task_id, gcode_file) app.loop()
def main(): config = ConfigService() # SETTING EXPECTED ARGUMENTS destination = config.get('general', 'bigtemp_path') # SETTING EXPECTED ARGUMENTS parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument("task_id", help="Task ID." ) parser.add_argument("-d", "--dest", help="Destination folder."), default=destination ) parser.add_argument("-i", "--intrinsic",help="Intrinsic camera parameters.", default='intrinsic.json' ) parser.add_argument("-o", "--output", help="Extrinsic camera parameters.", default='extrinsic.json' ) parser.add_argument("-W", "--width", help="Image width in pixels.", default=1296) parser.add_argument("-H", "--height", help="Image height in pixels.", default=972) parser.add_argument("-r", "--rotation", help="Image rotation.", default=0) parser.add_argument("-x", "--x-offset", help="X offset.", default=104) parser.add_argument("-y", "--y-offset", help="Y offset.", default=117) parser.add_argument("-z", "--z-offset", help="Z offset.", default=220) parser.add_argument("-b", "--base-height", help="Chessboard height of it's base.", default=0) parser.add_argument("--lang", help="Output language", default='en_US.UTF-8' ) # GET ARGUMENTS args = parser.parse_args() # INIT VARs task_id = int(args.task_id) destination = args.dest intrinsic_file = args.intrinsic monitor_file = config.get('general', 'task_monitor') # TASK MONITOR FILE (write stats & task info, ex: temperatures, speed, etc log_trace = config.get('general', 'trace') # TASK TRACE FILE width = int(args.width) height = int(args.height) rotation = int(args.rotation) x_offset = float(args.x_offset) y_offset = float(args.y_offset) z_offset = float(args.z_offset) base_height = float(args.base_height) output_file = args.output lang = args.lang output_dir = destination if not os.path.exists(output_dir): makedirs(output_dir) app = Extrinsic(log_trace, monitor_file, output_dir, output_file, width=width, height=height, rotation=rotation, lang=lang)
def install_plugin(plugin_filename, config=None, db=None): if not config: config = ConfigService() plugins_path = config.get('general', 'plugins_path') top, meta = extract_plugin(plugin_filename, config) if meta: slug = meta['plugin_slug'] plugin_dir = os.path.join(plugins_path, slug) installed_plugins = get_installed_plugins(config) active_plugins = get_active_plugins(config, db) was_active = False if slug in active_plugins: deactivate_plugin(slug, config, db) was_active = True if slug in installed_plugins: remove_plugin(slug, config) create_dir(plugin_dir) copy_files( os.path.join(top, '*'), plugin_dir) remove_dir(top) if was_active: activate_plugin(slug, config, db) return True return False
def extract_plugin(plugin_filename, config=None): """ Extract plugin file and verify that it IS a plugin archive """ if not config: config = ConfigService() top = "" meta = {} temp_dir = build_path( config.get('general', 'temp_path'), 'new_plugin' ) create_dir(temp_dir) cmd = 'unzip "{0}" -d "{1}" -o'.format(plugin_filename, temp_dir) try: subprocess.check_output( shlex.split(cmd) ) except subprocess.CalledProcessError as e: pass fn = find_file("meta.json", temp_dir) try: fn = fn[0] f = open(fn) meta = json.loads( f.read() ) top = os.path.dirname(fn) except Exception as e: remove_dir(temp_dir) return top, meta
def __init__(self, x1, x2, y1, y2, skip_homing=False, lang='en_US.UTF-8'): config = ConfigService() monitor_file = config.get('general', 'task_monitor') log_trace = config.get('general', 'trace') super(ProbeArea, self).__init__(log_trace, monitor_file, config=config, use_stdout=False, lang=lang) self.probe_length = 50 self.x1 = x1 self.x2 = x2 self.y1 = y1 self.y2 = y2 self.skip_homing = skip_homing
def main(): config = ConfigService() # SETTING EXPECTED ARGUMENTS parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument("-T", "--task-id", help="Task ID.", default=0) parser.add_argument("-e", "--extruder", help="Extruder to select.", default=0) parser.add_argument("-t", "--temp", help="Temperature used for PID tunind.", default=200) parser.add_argument("-c", "--cycles", help="Number of tuning cycles", default=8) parser.add_argument("--lang", help="Output language", default='en_US.UTF-8') # GET ARGUMENTS args = parser.parse_args() # INIT VARs task_id = int(args.task_id) # TASK ID monitor_file = config.get( 'general', 'task_monitor' ) # TASK MONITOR FILE (write stats & task info, ex: temperatures, speed, etc log_trace = config.get('general', 'trace') # TASK TRACE FILE temperature = int(args.temp) extruder = int(args.extruder) cycles = int(args.cycles) lang = args.lang app = PIDAutotune(log_trace, monitor_file, lang=lang) app_thread = Thread(target=app.run, args=([task_id, extruder, temperature, cycles])) app_thread.start() # app.loop() must be started to allow callbacks app.loop() app_thread.join()
def setLanguage(lang, domain='fab_diagnostic', config=None): if not config: config = ConfigService() locale_path = config.get('general', 'locale_path') tr = gettext.translation('fab_diagnostic', locale_path, fallback=True, languages=[lang]) _ = tr.ugettext return _
def main(): config = ConfigService() # SETTING EXPECTED ARGUMENTS parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument("-T", "--task-id", help="Task ID.", default=0) parser.add_argument("-n", "--num_probes", help="Number of probings per screw.", default=1, type=int) parser.add_argument("-s", "--skip_homing", action='store_true', help="Skip homing.") parser.add_argument("--lang", help="Output language", default='en_US.UTF-8') # GET ARGUMENTS args = parser.parse_args() # INIT VARs task_id = int(args.task_id) monitor_file = config.get('general', 'task_monitor') log_trace = config.get('general', 'trace') num_probes = args.num_probes skip_homing = args.skip_homing lang = args.lang print "num_probes: ", num_probes app = ManualBedLeveling(log_trace, monitor_file, config=config, lang=lang) app_thread = Thread(target=app.run, args=([task_id, num_probes, skip_homing])) app_thread.start() app.loop() # app.loop() must be started to allow callbacks app_thread.join()
def remove_plugin(plugin, config=None): if not config: config = ConfigService() plugins_path = config.get('general', 'plugins_path') plugin_dir = os.path.join( plugins_path, plugin ) if os.path.exists(plugin_dir): remove_dir(plugin_dir) return True return False
def startup(gcs): config = ConfigService() try: color = config.get('units', 'color') except KeyError: color = { 'r' : 255, 'g' : 255, 'b' : 255, } try: safety_door = config.get('units', 'safety')['door'] except KeyError: safety_door = 0 try: switch = config.get('units', 'switch') except KeyError: switch = 0 try: collision_warning = config.get('units', 'safety')['collision-warning'] except KeyError: collision_warning = 0 gcs.send("M728") gcs.send("M402") gcs.send("M701 S"+str(color['r'])) gcs.send("M702 S"+str(color['g'])) gcs.send("M703 S"+str(color['b'])) gcs.send("M732 S"+str(safety_door)) gcs.send("M714 S"+str(switch)) gcs.send("M734 S"+str(collision_warning))
class Database(object): """ """ def __init__(self, config = None): if not config: self.config = ConfigService() else: self.config = config self.lock = RLock() self.database_file = self.config.get('general', 'database') def get_connection(self): return sqlite3.connect(self.database_file)
def get_installed_plugins(config=None): if not config: config = ConfigService() plugins_path = config.get('general', 'plugins_path') result = {} for dirname in os.listdir(plugins_path): plugin_dir = os.path.join( plugins_path, dirname) plugin_meta = os.path.join(plugin_dir, "meta.json") if os.path.exists(plugin_meta): with open(plugin_meta) as f: meta = json.loads( f.read() ) result[dirname] = meta return result
def deactivate_plugin(plugin, config=None, db=None): if not config: config = ConfigService() if not db: db = Database(config) fabui_path = config.get('general', 'fabui_path') remove_file( os.path.join(fabui_path, 'application/controllers/Plugin_{0}.php'.format(plugin) ) ) remove_file( os.path.join(fabui_path, 'application/views/plugin/{0}'.format(plugin)) ) remove_file( os.path.join(fabui_path, 'assets/plugin/{0}'.format(plugin)) ) p = Plugin(db) p.query_by('name', plugin) p.delete() return True
def reset(): print "TOTUMDUINO: reset" config = ConfigService() reset_pin_s = config.get('totumduino', 'reset_pin', '17') reset_pins = reset_pin_s.split(',') try: #GPIO.setmode(GPIO.BOARD) GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) for pin in reset_pins: reset_pin = int(pin) GPIO.setup(reset_pin, GPIO.OUT) GPIO.output(reset_pin, GPIO.HIGH) time.sleep(0.5) GPIO.output(reset_pin, GPIO.LOW) time.sleep(0.5) for pin in reset_pins: reset_pin = int(pin) GPIO.output(reset_pin, GPIO.HIGH) GPIO.cleanup() except Exception as e: print e print "No GPIO support in QEMU simulation" time.sleep(1)
''' Set the highest baudrate available ''' def testBaud(port, baud_rate): ser = serial.Serial(port, baud_rate, timeout=0.5) ser.flushInput() ser.write("G0\r\n") serial_reply=ser.readline().rstrip() ser.close() return serial_reply != '' #serial_port = config.get('serial', 'port') baud_list=[250000, 115200] accepted_baud=0 for baud in baud_list: if(testBaud(configService.get('serial', 'PORT'), baud)): accepted_baud = baud break if accepted_baud > 0: print "Baud Rate available is: " + str(accepted_baud) else: accepted_baud=115200 if os.path.exists(SERIAL_INI) == False: file = open(SERIAL_INI, 'w+') file.write("[serial]\n") file.close() config = ConfigParser.ConfigParser()
def main(): from fabtotum.fabui.config import ConfigService dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) config = ConfigService() # Get PRISM BT address and use it as default value if it exists bt_addr = config.get('bluetooth', 'prism_bt_address', '') bt_addr_required = True if bt_addr: bt_addr_required = False # Setup arguments parser = argparse.ArgumentParser() parser.add_argument("command", help="Prism management command.") parser.add_argument("-v", dest='verbose', action='store_true', help="Verbose.", default=False) parser.add_argument("--arg-list", help="Comma separated argument list.", default=[]) parser.add_argument( "-a", "--address", help="Bluetooth address.", # In case there is no prism_bt_address preconfigured, fallback to asking for the address required=bt_addr_required, default=bt_addr) parser.add_argument("-P", "--port", help="L2C port", default=0x1001) args = parser.parse_args() cmd = args.command arg_list = args.arg_list bt_port = args.port bt_addr = args.address verbose = args.verbose if arg_list: arg_list = arg_list.split(',') # Ensure bluetooth is enabled p = subprocess.Popen(['connmanctl', 'enable', 'bluetooth'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = p.communicate() if 'Enabled bluetooth' == out.strip(): # Give bluetoothd some time to bring up the hci device time.sleep(3) if verbose: print "Bluetooth enabled" if cmd in ['connect', 'disconnect', 'trust', 'untrust']: adapter = Adapter() arg_list.append(adapter.Address) if verbose: print "Send: ", cmd print send_command(cmd, arg_list, bt_addr, bt_port, verbose)
class BTFactory(): def __init__(self, verbose=False): ## init attr self.verbose = verbose self._adapter = None self.controller_address = None self.config = ConfigService() self.status = None ## init adapater self._init_adapter() ####################### ## INIT BLUETOOTH ADAPTER ####################### def _init_adapter(self): dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) ## get bluetooth status self.status = bluetooth_status() ## enable bluetooth if is necessary if (self.status['powered'] == False): self.enable_bluetooth() self._adapter = Adapter(verbose=self.verbose) ## power adapter if necessary if not self._adapter.Powered: self._adapter.Powered = True self.controller_address = self._adapter.Address ####################### ## ENABLE BLUETOOTH ####################### def enable_bluetooth(self): if (self.verbose): print "Enabling bluetooth" enable_bluetooth() ## give time to bluetooth time.sleep(2) self.status = bluetooth_status() ####################### ## PAIR ####################### def pair(self, mac_address=None, look_for_name="PRISM"): if (self.status['paired'] != False): if (self.status['paired']['mac_address'] == mac_address or self.status['paired']['name'] == look_for_name): if (self.verbose): print "Already paired, skip pairing" return { 'paired': True, 'mac_address': self.status['paired']['mac_address'], 'name': self.status['paired']['name'] } if (self.verbose): print "trying to pair with: {0} [{1}]".format( look_for_name, mac_address) if (self.status['powered'] == False): self.enable_bluetooth() paired = False ## start pairing devices = self._adapter.discoverDevices(look_for_address=mac_address, timeout=60, verbose=self.verbose) for addrees in devices: device = devices[addrees] paired = True # mac_address = addrees if (self.verbose): print addrees, device.Name, device.Paired, device.Trusted, device.Adapter # mac_address = addrees if not device.Paired: if (self.verbose): print "Pairing.." device.Pair() device.Trusted = True if paired: if (self.verbose): print "Paired with {0} [{1}]".format(look_for_name, mac_address) ## save to config file self.config.set('bluetooth', 'prism_bt_address', str(mac_address)) self.config.set('bluetooth', 'prism_bt_name', str(look_for_name)) self.config.save('bluetooth') ### trust us ## give time to bluetooth time.sleep(2) send_command('trust', [self.controller_address], mac_address, verbose=self.verbose) return { 'paired': paired, 'mac_address': mac_address, 'name': look_for_name } ####################### ## UNPAIR ####################### def unpair(self, mac_address): try: self._adapter.RemoveDevice(mac_address) ### tell also device to unpair send_command('disconnect', [self.controller_address], mac_address, verbose=self.verbose) # send_command('unpair', [self.controller_address], mac_address, verbose=self.verbose) ## save to config file self.config.set('bluetooth', 'prism_bt_address', '') self.config.set('bluetooth', 'prism_bt_name', '') self.config.set('bluetooth', 'prism_bt_network_address', '') self.config.save('bluetooth') except Exception as e: pass return True ####################### ## SCAN ####################### def scan(self): if (self.verbose): print "Scan for devices..." return scan('list') ################################### ## AUTO PAIR AND CONNECT TO PRISM ################################### def auto_connection(self, name="PRISM", mac_address=None): if (self.status['paired'] == False): if (mac_address == None or mac_address == ""): devices = self.scan() for device in devices: if (device['name'] == name): mac_address = device['mac'] else: if (mac_address == None or mac_address == ""): mac_address = self.status['paired']['mac_address'] if (self.verbose): print "Autoconnection to {0} [{1}]".format(name, mac_address) pairing_result = self.pair(mac_address=mac_address, look_for_name=name) mac_address = pairing_result['mac_address'] paired = pairing_result['paired'] connection = None if (paired): connection = self.send_command('connect', [], mac_address) return {'connection': connection, 'paired': paired} ################################### ## SEN COMMAND TO PRISM ################################### def send_command(self, command, args=[], mac_address=None, port=0x1001): if (mac_address == None or mac_address == ""): if self.status['paired'] != False: if "mac_address" in self.status['paired']: mac_address = self.status['paired']['mac_address'] else: return {'error': _("No connected device")} socket = bluetooth.BluetoothSocket(bluetooth.L2CAP) socket.settimeout(3) if (self.verbose): print "Trying to connect to {0} on port {1}".format( mac_address, port) try: socket.connect((mac_address, port)) #bluetooth.set_packet_timeout(mac_address, 0) if command in ['connect', 'disconnect', 'trust', 'untrust']: args.append(self._adapter.Address) if command in ['connect', 'rpc']: tether_address = get_ip_address('tether') if (tether_address != 'n.a'): args.append(tether_address) args.append(self.config.get('xmlrpc', 'xmlrpc_port')) data = json.dumps({'cmd': command, 'args': args}) if self.verbose: print "Data sent {0}".format(data) ## send data socket.send(data) # get data reply = socket.recv(1024) # close socket socket.close() if self.verbose: print "Data received:".format(reply) response = json.loads(reply) ## save network address if (command in ['connect', 'network-address']): self.config.set('bluetooth', 'prism_bt_network_address', response['reply']) self.config.save('bluetooth') if (command == 'disconnect'): self.config.set('bluetooth', 'prism_bt_network_address', '') self.config.save('bluetooth') return {'command': command, 'response': response['reply']} except Exception as e: if self.verbose: print "Error: {0}".format(e) return {'error': str(e)}
from watchdog.events import PatternMatchingEventHandler # Import internal modules from fabtotum.fabui.config import ConfigService from fabtotum.fabui.gpusher import GCodePusher import fabtotum.fabui.macros.general as general_macros import fabtotum.fabui.macros.printing as print_macros config = ConfigService() # SETTING EXPECTED ARGUMENTS parser = argparse.ArgumentParser() parser.add_argument("file", help="gcode file to execute") parser.add_argument("command_file", help="command file") parser.add_argument("task_id", help="id_task") parser.add_argument("monitor", help="monitor file", default=config.get('general', 'task_monitor'), nargs='?') parser.add_argument("trace", help="trace file", default=config.get('general', 'trace'), nargs='?') parser.add_argument("--ext_temp", help="extruder temperature (for UI feedback only)", default=180, nargs='?') parser.add_argument("--bed_temp", help="bed temperature (for UI feedback only)", default=50, nargs='?') parser.add_argument("--standalone", help="call macros internally", default=False, nargs='?') # GET ARGUMENTS args = parser.parse_args() # INIT VARs gcode_file = args.file # GCODE FILE command_file = args.command_file # OVERRIDE DATA FILE task_id = args.task_id # TASK ID monitor_file = args.monitor # TASK MONITOR FILE (write stats & task info, es: temperatures, speed, etc log_trace = args.trace # TASK TRACE FILE ext_temp_target = args.ext_temp # EXTRUDER TARGET TEMPERATURE (previously read from file)
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 NotifyService(object): """ Notification service. Handles all notification by sending the messages to an opened websocket and writing the same messages to a NOTIFY_FILE file as a fallback in case websocket is not supported. """ def __init__(self, WebSocket=None, notify_file=None, config=None): self.notify_lock = RLock() if not config: self.config = ConfigService() else: self.config = config if not notify_file: notify_file = self.config.get('general', 'notify_file') if not WebSocket: SOCKET_HOST = self.config.get('socket', 'host') SOCKET_PORT = self.config.get('socket', 'port') self.ws = WebSocketClient('ws://' + SOCKET_HOST + ':' + SOCKET_PORT + '/') self.ws.connect() else: self.ws = WebSocket self.notify_file = notify_file self.backtrack = int(self.config.get('notify', 'backtrack', 30)) self.event_id = 0 self.events = [] def notify(self, event_type, event_data): with self.notify_lock: self.__add_event(event_type, event_data) self.__send_message(event_type, event_data) def get_last(self): if self.events: return self.events[-1] return None def __add_event(self, event_type, event_data): """ Add a new event to the event list and write the list to NOTIFY_FILE. """ self.event_id += 1 # Increment the event ID number event = {'id': self.event_id, 'type': event_type, 'data': event_data} if len(self.events) >= self.backtrack: self.events = self.events[1:] + [event] else: self.events.append(event) wrapper = {'events': self.events, 'last_event': event} with open(self.notify_file, 'w') as f: f.write(json.dumps(wrapper)) def __send_message(self, type, data): """ Send message to WebSocket server. :param type: Message type :param data: Message data :type type: string :type data: string """ message = {'type': type, 'data': data} self.ws.send(json.dumps(message))
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 MyFabtotumCom: RESPONSE_CODES_DESCRIPTION = { SERVICE_SUCCESS: 'SERVICE_SUCCESS', SERVICE_UNAUTHORIZED: 'SERVICE_UNAUTHORIZED', SERVICE_FORBIDDEN: 'SERVICE_FORBIDDEN', SERVICE_SERVER_ERROR: 'SERVICE_SERVER_ERROR', SERVICE_INVALID_PARAMETER: 'SERVICE_INVALID_PARAMETER', SERVICE_ALREADY_REGISTERED: 'SERVICE_ALREADY_REGISTERED', SERVICE_PRINTER_UNKNOWN: 'SERVICE_PRINTER_UNKNOWN' } STATUS = { 0: 'AVAILABLE', 1: 'BUSY', 2: 'BUSY', 3: 'PAUSED', 4: 'PAUSED', } def __init__(self, gcs, logger, config=None): if config: self.config = config else: self.config = ConfigService() self.gcs = gcs self.db = Database(self.config) self.log = logger self.url = self.config.get('my.fabtotum.com', 'myfabtotum_url') self.api_version = self.config.get('my.fabtotum.com', 'myfabtotum_api_version') self.thread_polling = None self.thread_update = None self.thread_reload = None self.running = False self.jsonrpc_version = "2.0" self.request_timeout = 5 self.polling_interval = 5 self.info_interval = (60 * 30) # 30 minutes self.internal_update_interval = (60 * 5) # 5 minutes self.id_counter = 0 self.leds_colors = {} #self.mac_address = None #self.serial_number = None #self.fab_id = None #self.unit_name = None #self.batch_number = None #self.fw_version = None self.__init_vars() def __init_vars(self): """ init vars """ self.mac_address = self.getMACAddres() self.ip_lan = self.getIPLan() self.serial_number = self.getSerialNumber() self.fab_id = self.getFabID() self.unit_name = self.getUnitName() #self.batch_number = self.getBatchNumer() #self.fw_version = self.getFwVersion() self.unit_color = self.getUnitColor() self.leds_colors = self.getLedsColors() self.fabui_version = self.getFabUiVersion() def call(self, method, params): """ make jsonrpc call to my.fabtotum.com remote server """ try: self.id_counter += 1 headers = { 'content-type': 'application/json', 'user-agent': 'fabtotum' } payload = { "method": method, "params": params, "jsonrpc": self.jsonrpc_version, "id": self.id_counter, } response = requests.post(self.url, data=json.dumps(payload), headers=headers, timeout=self.request_timeout, verify=False).json() if "result" in response: return response['result'] elif "error" in response: self.log.debug("MyFabtotumCom - {0} : {1} : {2}".format( response['error']['message'], response['error']['code'], response['error']['data'])) return False except requests.exceptions.RequestException as e: self.log.debug("MyFabtotumCom - {0}".format(e)) self.log.debug("MyFabtotumCom - {0}".format(payload)) return False def __getSystemConfig(self, value): """ get value from system config table """ sysconfig = SysConfig(self.db) sysconfig.query_by('key', value) return sysconfig['text'] def getFabID(self): """ """ user = User(self.db) user.query_by('role', 'administrator') settings = json.loads(user['settings']) if "fabid" in settings: return settings['fabid']['email'] else: return False def getMACAddres(self, iface='eth0'): """ get printer mac address """ return get_mac_address('eth0') def getSerialNumber(self): """ get printer serial number """ return self.__getSystemConfig('serial_number') def getUnitName(self): """ get unit name """ return self.__getSystemConfig('unit_name') def getUnitColor(self): """ get unit color """ return self.__getSystemConfig('unit_color') def getLedsColors(self): """ get ambient leds lights """ try: return self.config.get('settings', 'color') except: return {'r': 255, 'g': 255, 'b': 255} def getBatchNumer(self): """ get batch number """ try: reply = self.gcs.send("M763", group='gcode') return reply[0].strip() except: return 0 def getModel(self): """ get fabtotum model """ batch_number = self.getBatchNumer() model = fabtotum_model(batch_number) return "{0} ({1})".format(model, batch_number) def getFwVersion(self): """ get firmware version """ try: reply = self.gcs.send("M765", group='gcode') return reply[0].strip() except: return "N.D." def getFabUiVersion(self): """ get fabui version """ bundle = get_local_bundle('fabui') if bundle: return bundle['version'] else: return None def getIPLan(self): """ return IP address """ return get_ip_address('wlan0') def getState(self): """ printer's state """ return self.STATUS[self.gcs.getState()] def identify(self): """ remote command identify printer""" self.log.info("MyFabtotumCom - Identify printer") # reload infos and send all to remote server self.reload(update=True) self.gcs.send("M300", group='gcode') self.gcs.send("M150 R0 U255 B255 S50", group='gcode') time.sleep(3) self.gcs.send("M701 S{0}".format(self.leds_colors['r']), group='gcode') self.gcs.send("M702 S{0}".format(self.leds_colors['g']), group='gcode') self.gcs.send("M703 S{0}".format(self.leds_colors['b']), group='gcode') self.gcs.send("M300", group='gcode') def reboot(self): """ remote command reboot unit """ os.system('reboot') def lock(self): """ remote command lock printer """ self.log.info("MyFabtotumCom - Lock printer") def unlock(self): """ remote command unlock printer """ self.log.info("MyFabtotumCom - Unlock printer") def switch_off(self): """ remote commnad switch off """ os.system("poweroff") def end_job(self): """ remote command end active task """ self.log.info("MyFabtotumCom - Abort task") self.gcs.abort() def fab_polling(self): """ ping my.fabtotum.com remote server for new commands """ params = { "serialno": self.serial_number, "mac": self.mac_address, "state": self.getState(), "apiversion": self.api_version, "iplan": self.ip_lan, "fabuiversion": self.fabui_version } result = self.call('fab_polling', params) if result: if result["status_code"] == SERVICE_SUCCESS: if "command" in result: try: getattr(self, result["command"].lower())() except AttributeError: self.log.debug( "MyFabtotumCom - {0} : command not valid".format( result["command"])) except: self.log.debug( "MyFabtotumCom - Unexpected error: {0}".format( sys.exc_info()[0])) if "pollinterval" in result: self.polling_interval = result['pollinterval'] else: self.log.debug("MyFabtotumCom - {0}".format( self.RESPONSE_CODES_DESCRIPTION[result["status_code"]])) def fab_info_update(self): """ update data on my.fabtotum.com remote server """ head = self.config.get_current_head_info() params = { "serialno": self.serial_number, "mac": self.mac_address, "data": { "name": self.unit_name, "model": self.getModel(), "head": head["name"], "fwversion": self.getFwVersion(), "iplan": self.ip_lan, 'color': self.unit_color, 'fabuiversion': self.fabui_version }, "apiversion": self.api_version, } result = self.call('fab_info_update', params) if result: self.log.debug("MyFabtotumCom - fab_info_update: {0} - {1}".format( self.RESPONSE_CODES_DESCRIPTION[result["status_code"]], params)) def start(self): """ start server """ self.running = True self.thread_polling = Thread(name="MyFabtotumCom_Polling", target=self.__thread_polling) self.thread_polling.start() self.thread_update = Thread(name="MyFabtotumCom_InfoUpdate", target=self.__thread_update) self.thread_update.start() self.thread_reload = Thread(name="MyFabtotumCom_Reload", target=self.__thread_reload) self.thread_reload.start() def stop(self): self.running = False def reload(self, update=True): """ reload settings """ self.mac_address = self.getMACAddres() self.ip_lan = self.getIPLan() self.serial_number = self.getSerialNumber() self.fab_id = self.getFabID() self.unit_name = self.getUnitName() #self.batch_number = self.getBatchNumer() #self.fw_version = self.getFwVersion() self.unit_color = self.getUnitColor() self.leds_colors = self.getLedsColors() self.fabui_version = self.getFabUiVersion() #### update info if (update == True): self.fab_info_update() self.log.debug("MyFabtotumCom - Settings reloaded") def __thread_polling(self): """ polling thread """ self.log.debug("MyFabtotumCom Polling_thread: started") while self.running: if self.fab_id: self.fab_polling() time.sleep(self.polling_interval) def __thread_update(self): """ info update thread """ self.log.debug("MyFabtotumCom InfoUpdate_thread: started") while self.running: if self.fab_id: self.fab_info_update() time.sleep(self.info_interval) def __thread_reload(self): """ internal update """ self.log.debug("MyFabtotumCom Reload_thread: started") while self.running: if self.fab_id: self.reload(update=False) time.sleep(self.internal_update_interval) def loop(self): if self.thread_polling: self.thread_polling.join() if self.thread_update: self.thread_update.join() if self.thread_reload: self.thread_reload.join()
from fabtotum.os.monitor.gpiomonitor import GPIOMonitor def signal_handler(signal, frame): print "You pressed Ctrl+C!" print "Shutting down services. Please wait..." ws.close() gcserver.stop() gcservice.stop() observer.stop() usbMonitor.stop() gpioMonitor.stop() config = ConfigService() # Load configuration LOCK_FILE = config.get('general', 'lock') TRACE = config.get('general', 'trace') COMMAND = config.get('general', 'command') MACRO_RESPONSE = config.get('general', 'macro_response') TASK_MONITOR = config.get('general', 'task_monitor') EMERGENCY_FILE = config.get('general', 'emergency_file') ################################################################## SOCKET_HOST = config.get('socket', 'host') SOCKET_PORT = config.get('socket', 'port') ################################################################## HW_DEFAULT_SETTINGS = config.get('hardware', 'default_settings') HW_CUSTOM_SETTINGS = config.get('hardware', 'custom_settings') ################################################################## USB_DISK_FOLDER = config.get('usb', 'usb_disk_folder') USB_FILE = config.get('usb', 'usb_file') ##################################################################
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)
xmlrpc_pidfile = args.xmlrpc_pidfile btagent_pidfile = args.btagent_pidfile no_xmlrpc = args.no_xmlrpc gpio_pidfile = args.gpio_pidfile no_gpiomonitor = args.no_gpiomonitor no_btagent = args.no_btagent no_monitor = args.no_monitor #myfabtotumcom_pidfile = args.myfabtotumcom_pidfile with open(pidfile, 'w') as f: f.write(str(os.getpid())) config = ConfigService() # Load configuration TRACE = config.get('general', 'trace') TASK_MONITOR = config.get('general', 'task_monitor') TEMP_MONITOR_FILE = config.get('general', 'temperature') NOTIFY_FILE = config.get('general', 'notify_file') LOG_LEVEL = config.get('general', 'log_level', 'INFO') ################################################################## SOCKET_HOST = config.get('socket', 'host') SOCKET_PORT = config.get('socket', 'port') ################################################################## HW_DEFAULT_SETTINGS = config.get('hardware', 'settings') ################################################################## USB_DISK_FOLDER = config.get('usb', 'usb_disk_folder') USB_FILE = config.get('usb', 'usb_file') ################################################################## SERIAL_PORT = config.get('serial', 'PORT') SERIAL_BAUD = config.get('serial', 'BAUD')
class UpdateFactory: 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 getTasks(self): return self.tasks def getBundles(self): return self.remote.getBundles() def getFirmware(self): return self.remote.getFirmware() def getBoot(self): return self.remote.getBoot() def getPlugins(self): return self.remote.getPlugins() def getEndpoint(self, name): if name == "bundle": return self.remote.getColibriEndpoint() elif name == "firmware": return self.remote.getFirmwareEndpoint() elif name == "boot": return self.remote.getColibriEndpoint() elif name == "plugins": return self.remote.getPluginsEndpoint() def getTempFolder(self): return self.config.get('general', 'bigtemp_path') def addTask(self, task): task.setFactory(self) self.tasks.append(task) def update(self): if self.notify_update: self.notify_update(self) def getCurrentStatus(self): task = self.getTaskByName(self.task) if task: return task.getStatus() return "" def getTaskByName(self, name): if not name: return None for task in self.tasks: if task.getName() == name: return task return None def setStatus(self, status): self.status = status self.update() def getStatus(self): return self.status def setCurrentTask(self, task): self.task = task def getCurrentTask(self): return self.task def getCurrentName(self): task = self.getTaskByName(self.task) if task: return task.getName() return "" def getCurrentType(self): task = self.getTaskByName(self.task) if task: return task.getType() return "" def setRebootRequired(self, reboot): self.reboot_required = reboot def getRebootRequired(self): return self.reboot_required def serialize(self): data = { "current": { "name": self.getCurrentName(), "type": self.getCurrentType(), "status": self.getStatus(), "task": self.getCurrentTask(), "reboot": self.getRebootRequired() }, "tasks": [] } #~ for task in self.tasks: #~ data["tasks"][task.getName()] = task.serialize() for task in self.tasks: data["tasks"].append(task.serialize()) return data
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()
class RemoteVersion: def __init__(self, arch='armhf', mcu='atmega1280', config=None): self.config = config if not config: self.config = ConfigService() self.colibri_endpoint = self.config.get('updates', 'colibri_endpoint') self.firmware_endpoint = self.config.get('updates', 'firmware_endpoint') self.plugin_endpoint = self.config.get('updates', 'plugins_endpoint') self.arch = arch self.mcu = mcu self.colibri = None self.firmware = None self.plugins = None self.setColibri() self.setFirmware() self.setPlugins() def getRemoteData(self, endpoint): curl = pycurl.Curl() buffer = BytesIO() curl.setopt(pycurl.URL, endpoint) curl.setopt(pycurl.TIMEOUT, 30) curl.setopt(pycurl.FOLLOWLOCATION, 1) curl.setopt(pycurl.SSL_VERIFYPEER, 0) curl.setopt(pycurl.SSL_VERIFYHOST, 0) curl.setopt(pycurl.MAXREDIRS, 5) curl.setopt(curl.WRITEDATA, buffer) curl.perform() return buffer.getvalue() def setColibri(self): self.colibri = json.loads( self.getRemoteData( os.path.join(self.colibri_endpoint, self.arch, "version.json"))) def setFirmware(self): self.firmware = json.loads( self.getRemoteData( os.path.join(self.firmware_endpoint, "fablin", self.mcu, "version.json"))) def setPlugins(self): self.plugins = json.loads( self.getRemoteData( os.path.join(self.plugin_endpoint, "cached.json"))) def getColibri(self): return self.colibri def getBundles(self): return self.colibri['bundles'] def getBoot(self): return self.colibri['boot'] def getImages(self): return self.colibri['images'] def getFirmware(self): if 'firmware' in self.firmware: return self.firmware['firmware'] return {} def getPlugins(self): return self.plugins def getColibriEndpoint(self): return os.path.join(self.colibri_endpoint, self.arch) def getFirmwareEndpoint(self): return os.path.join(self.firmware_endpoint, 'fablin', self.mcu) def getPluginsEndpoint(self): return self.firmware_endpoint
def main(): config = ConfigService() # SETTING EXPECTED ARGUMENTS destination = config.get('general', 'bigtemp_path') parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter) #~ subparsers = parser.add_subparsers(help='sub-command help', dest='type') parser.add_argument("-T", "--task-id", help="Task ID.", default=0) parser.add_argument("-U", "--user-id", help="User ID. (future use)", default=0) parser.add_argument("-O", "--object-id", help="Object ID.", default=0) parser.add_argument("-N", "--object-name", help="Object name.", default='') parser.add_argument("-F", "--file-name", help="File name.", default='') parser.add_argument("-d", "--dest", help="Destination folder.", default=destination) parser.add_argument("-s", "--slices", help="Number of slices.", default=100) parser.add_argument("-i", "--iso", help="ISO.", default=400) parser.add_argument("-p", "--power", help="Scan laser power 0-255.", default=230) parser.add_argument("-W", "--width", help="Image width in pixels.", default=1296) parser.add_argument("-H", "--height", help="Image height in pixels", default=972) parser.add_argument("-C", "--camera", help="Camera version", default='v1') parser.add_argument("-b", "--begin", help="Begin scanning from X.", default=0) parser.add_argument("-e", "--end", help="End scanning at X.", default=100) parser.add_argument("-y", "--y-offset", help="Y offset.", default=117) parser.add_argument("-z", "--z-offset", help="Z offset.", default=145) parser.add_argument("-a", "--a-offset", help="A offset/rotation.", default=0) parser.add_argument("-o", "--output", help="Output point cloud file.", default=os.path.join(destination, 'cloud.asc')) parser.add_argument("--lang", help="Output language", default='en_US.UTF-8') parser.add_argument("--email", help="Send an email on task finish", action='store_true', default=False) parser.add_argument("--shutdown", help="Shutdown on task finish", action='store_true', default=False) # GET ARGUMENTS args = parser.parse_args() slices = int(args.slices) destination = args.dest iso = int(args.iso) power = int(args.power) start_x = float(args.begin) end_x = float(args.end) width = int(args.width) height = int(args.height) z_offset = float(args.z_offset) y_offset = float(args.y_offset) a_offset = float(args.a_offset) task_id = int(args.task_id) user_id = int(args.user_id) object_id = int(args.object_id) object_name = args.object_name file_name = args.file_name camera_version = args.camera if task_id == 0: standalone = True else: standalone = False cloud_file = args.output lang = args.lang send_email = bool(args.email) monitor_file = config.get( 'general', 'task_monitor' ) # TASK MONITOR FILE (write stats & task info, es: temperatures, speed, etc log_trace = config.get('general', 'trace') # TASK TRACE FILE scan_dir = os.path.join(destination, "images") if not os.path.exists(scan_dir): makedirs(scan_dir) ##### delete files cleandirs(scan_dir) camera_path = os.path.join(config.get('hardware', 'cameras')) ################################################################################ print 'SWEEP SCAN MODULE STARTING' print 'scanning from' + str(start_x) + "to" + str(end_x) print 'Num of scans : [{0}]'.format(slices) print 'ISO setting : ', iso print 'Resolution : ', width, '*', height, ' px' print 'Y-offset (y) : ', y_offset print 'Z-offset (z) : ', z_offset print 'A-Offset. : ', a_offset #ESTIMATED SCAN TIME ESTIMATION estimated = (slices * 2) / 60.0 if estimated < 1: estimated *= 60.0 unit = "Seconds" else: unit = "Minutes" print 'Estimated Scan time =', str(estimated) + " " + str( unit) + " [Pessimistic]" app = SweepScan(log_trace, monitor_file, scan_dir, standalone=standalone, width=width, height=height, iso=iso, power=power, lang=lang, send_email=send_email) app_thread = Thread(target=app.run, args=([ task_id, object_id, object_name, file_name, camera_path, camera_version, start_x, end_x, a_offset, y_offset, z_offset, slices, cloud_file ])) app_thread.start() # app.loop() must be started to allow callbacks app.loop() app_thread.join()
def main(): config = ConfigService() # SETTING EXPECTED ARGUMENTS parser = argparse.ArgumentParser( add_help=False, formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument("-T", "--task-id", help="Task ID.", default=0) parser.add_argument("-U", "--user-id", help="User ID. (future use)", default=0) parser.add_argument("--address", help="Remove server address.") parser.add_argument("--port", help="Remove server port.", default=9898) parser.add_argument("-d", "--dest", help="Destination folder.", default=config.get('general', 'bigtemp_path')) parser.add_argument("-s", "--slices", help="Number of slices.", default=100) parser.add_argument("-i", "--iso", help="ISO.", default=400) parser.add_argument("-W", "--width", help="Image width in pixels.", default=1920) parser.add_argument("-H", "--height", help="Image height in pixels", default=1080) parser.add_argument("-b", "--begin", help="Begin scanning from X.", default=0) parser.add_argument("-e", "--end", help="End scanning at X.", default=360) parser.add_argument("-z", "--z-offset", help="Z offset.", default=0) parser.add_argument("-y", "--y-offset", help="Y offset.", default=0) parser.add_argument("-a", "--a-offset", help="A offset/rotation.", default=0) parser.add_argument("--lang", help="Output language", default='en_US.UTF-8') parser.add_argument( "--standalone", action='store_true', help="Standalone operation. Does all preparations and cleanup.") parser.add_argument('--help', action='help', help="Show this help message and exit") parser.add_argument("--email", help="Send an email on task finish", action='store_true', default=False) parser.add_argument("--shutdown", help="Shutdown on task finish", action='store_true', default=False) # GET ARGUMENTS args = parser.parse_args() slices = int(args.slices) destination = args.dest host_address = args.address host_port = int(args.port) iso = int(args.iso) start_a = float(args.begin) end_a = float(args.end) width = int(args.width) height = int(args.height) z_offset = float(args.z_offset) y_offset = float(args.y_offset) a_offset = float(args.a_offset) standalone = args.standalone task_id = int(args.task_id) lang = args.lang send_email = bool(args.email) monitor_file = config.get( 'general', 'task_monitor' ) # TASK MONITOR FILE (write stats & task info, es: temperatures, speed, etc log_trace = config.get('general', 'trace') # TASK TRACE FILE scan_dir = os.path.join(destination, "images") if not os.path.exists(scan_dir): makedirs('scan_dir') ##### delete files cleandirs(scan_dir) ################################################################################ app = PhotogrammetryScan(log_trace, monitor_file, scan_dir, standalone=standalone, width=width, height=height, iso=iso, host_address=host_address, host_port=host_port, lang=lang, send_email=send_email) app_thread = Thread(target=app.run, args=([task_id, start_a, end_a, y_offset, slices])) app_thread.start() app.loop() # app.loop() must be started to allow callbacks app_thread.join()
#!/bin/env python # -*- coding: utf-8; -*- # Import internal modules from fabtotum.fabui.config import ConfigService cfg = ConfigService() print cfg.get('serial', 'baud') print cfg.get('serial', 'port') print cfg.get('task', 'lock_file')