def set_groups(self, groups): if type(groups) == list: self.logger.info("Groups are set correctly for %s %s" % (str(self.usb_info), str(groups))) self.groups = groups else: config.create_error_report(999, "Invalid workgroups format - type must be list: " + str(groups), self.usb_info, self.logger, is_blocking=False)
def flash_firmware(self): firmware = self.find_firmware_file() if firmware: self.logger.info( "Prepare to flash device with firmware:{0}.".format(firmware)) file_size = os.path.getsize(firmware) version = "0.0.0" ret1 = self.dispatch("M114 A{0}\n".format(version)) message = "M650 A{0}\n".format(file_size) ret2 = self.dispatch(message) if 'ok' in ret1 and 'ok' in ret2: with open(firmware, 'rb') as f: while True: buf = f.read(64) if not buf: break self.ep_out.write(buf) ret = [] while (len(ret) != len(buf)): ret += self.ep_in.read(len(buf), READ_TIMEOUT) assert (''.join([chr(x) for x in ret]) in buf) self.logger.debug(".") self.logger.info("Flashing complete.") new_version = self.get_firmware_version( os.path.basename(firmware)) self.dispatch("M114 A{0}\n".format(new_version)) self.dispatch("M630\n") self.dev.reset() self.logger.info("Rebooting to new firmware...") else: config.create_error_report(601, "Error - no firmware found.", self.usb_info, self.logger, is_blocking=True)
def start_main_loop(self): self.last_flush_time = 0 self.detector = usb_detect.USBDetector() self.http_client = http_client.HTTPClient() while not self.stop_flag: self.updater.timer_check_for_updates() self.time_stamp() self.detected_printers = self.detector.get_printers_list() if self.virtual_printer_enabled: self.detected_printers.append( {"VID" : "ZZZZ", "PID": "ZZZZ", "SNR": "0", "COM": None} ) self.connect_new_printers() for pi in self.printer_interfaces: if pi.usb_info not in self.detected_printers: if not pi.error_state == "error": config.create_error_report(99, "Printer is no longer detected as USB device.", pi.usb_info, self.logger, is_blocking=True) if not pi.is_alive(): if not pi.stop_flag: self.logger.warning("Printer interface of %s had crushed" % pi.usb_info) self.logger.info('Removing %s from printer list' % pi.usb_info) self.printer_interfaces.remove(pi) if not self.stop_flag: time.sleep(self.MAIN_LOOP_SLEEP) now = time.time() if now - self.last_flush_time > self.LOG_FLUSH_TIME: self.last_flush_time = now self.flush_log() self.quit()
def update(self): if self.update_flag: self.logger.info('Updating client...') update_file_name = config.get_settings( )['update']['update_file_name'] try: urllib.urlretrieve( config.get_settings()['update']['update_file_url'] + update_file_name, update_file_name) except Exception as e: error_message = 'Update failed!\nReason: error while downloading.\nDetails: ' + str( e) config.create_error_report(0, error_message, None, self.logger, is_blocking=True) return error_message else: error = self.extract_update(update_file_name) if error: return error self.logger.info('...client successfully updated!') self.update_flag = False log.send_logs() log.clear_logs()
def reading(self): while not self.stop_flag: line = self.connection.recv() if line is None: # None means error reading from printer, but "" is ok self.operational_flag = False time.sleep(self.PAUSE_ON_ERROR_READING_PORT) elif not line or "wait" in line: continue elif self.is_ok(line): self.ready_for_command = True self.operational_flag = True self.check_temperature_and_position(line) elif line.startswith("T"): # FIXME T is too ambitious self.parse_waiting_temperature_updates(line) self.operational_flag = True elif self.check_for_resend_requests(line): self.logger.debug(line) self.operational_flag = True self.ready_for_command = True elif line.startswith('Error'): if not ("checksum" in line or "Checksum" in line or "expected line" in line or "Line Number is not Last Line Number+1" in line or "Format error" in line): is_blocking = self.BOARD_RESET_GCODE in line or "disabling all for safety!" in line self.operational_flag = False config.create_error_report(201, line, self.usb_info, self.logger, is_blocking=is_blocking) else: self.logger.debug(line) elif line.startswith('DEBUG'): self.logger.info(line) else: self.logger.warning("Special message: " + line.strip())
def flash_firmware(self): firmware = self.find_firmware_file() if firmware: self.logger.info("Prepare to flash device with firmware:{0}.".format(firmware)) file_size = os.path.getsize(firmware) version = "0.0.0" ret1 = self.dispatch("M114 A{0}\n".format(version)) message = "M650 A{0}\n".format(file_size) ret2 = self.dispatch(message) if 'ok' in ret1 and 'ok' in ret2: with open(firmware, 'rb') as f: while True: buf = f.read(64) if not buf: break self.ep_out.write(buf) ret = [] while (len(ret) != len(buf)): ret += self.ep_in.read(len(buf), READ_TIMEOUT) assert (''.join([chr(x) for x in ret]) in buf) self.logger.debug(".") self.logger.info("Flashing complete.") new_version = self.get_firmware_version(os.path.basename(firmware)) self.dispatch("M114 A{0}\n".format(new_version)) self.dispatch("M630\n") self.dev.reset() self.logger.info("Rebooting to new firmware...") else: config.create_error_report(601, "Error - no firmware found.", self.usb_info, self.logger, is_blocking=True)
def monitoring(self): self.logger.info("Monitoring thread started") while not self.monitoring_stop and not self.stop_flag: self.connection.send("M105") self.connection.send("M119") self.connection.send("M27") answer = self.readout() if not answer: self.operational_flag = False message = "Printer not answering in monitoring. Printer lost." config.create_error_report(606, message, self.usb_info, self.logger, is_blocking=True) break self.parse_temperature(answer) self.operational_flag = True if self.STATE_READY in answer: self.printing_flag = False else: self.printing_flag = True progress_match = self.progress_re.match(answer) if progress_match: self.lines_sent = int(progress_match.group(1)) self.total_gcodes = int(progress_match.group(2)) if self.total_gcodes > 0: self.percent = int(self.lines_sent / float(self.total_gcodes) * 100) time.sleep(0.1) self.logger.info("Monitoring thread stopped")
def pack(self, target, *args, **kwargs): if target == 'user_login': data = { 'login': {'user': args[0], 'password': args[1]}, 'platform': platforms.PLATFORM, 'host_mac': self.mac, 'local_ip' : self.local_ip, 'version': version.version} if 'disposable_token' in kwargs: data['login']['disposable_token'] = kwargs['disposable_token'] path = self.user_login_path #self.logger.debug(data) elif target == 'printer_login': data = { 'user_token': args[0], 'printer': args[1], "version": version.version, "data_time": time.ctime(), "camera": config.get_app().camera_controller.get_current_camera_name() } path = self.printer_login_path elif target == 'command': data = { 'printer_token': args[0], 'report': args[1], 'command_ack': args[2] } if not data['command_ack']: data.pop('command_ack') path = self.command_path elif target == 'camera': data = { 'user_token': args[0], 'camera_number': args[1], 'camera_name': args[2], 'file_data': args[3], 'host_mac': self.mac} path = self.camera_path elif target == 'cloudsync': data = { 'user_token': args[0], 'file_data': args[1]} path = self.cloudsync_path else: config.create_error_report(4, 'No such target for packaging: ' + target, None, self.logger, is_blocking=False) data, path = None, None for key, value in kwargs.items(): data[key] = value return path, json.dumps(data)
def cancel(self): if not self.cancel_download(): if self.profile.get('no_DTR') and self.in_heating: message = "This printer model can't cancel during heating." config.create_error_report(257, message, self.usb_info, self.logger, is_blocking=False) return False else: self.stop_flag = True if self.print_thread: self.print_thread.cancel() self.print_thread.join() self.read_thread.join() self.temperature_request_thread.join() self.reset() self.stop_flag = False try: self.init() self.logger.info("Successful cancel") except RuntimeError: message = "Can't reconnect to printer after cancel." config.create_error_report(255, message, self.usb_info, self.logger, is_blocking=True)
def check_operational_state(self): if not self.printer or self.stop_flag: pass elif self.printer.stop_flag: pass elif self.printer.is_operational( ): #TODO check this operation for thread safety self.last_operational_time = time.time() self.error_state = None self.last_errors = [] elif not self.error_state: message = "Printer is not operational" config.create_error_report(77, message, self.usb_info, self.logger, is_blocking=False) elif self.error_state != "error" and self.last_operational_time + self.READY_TIMEOUT < time.time( ): message = "Not operational timeout reached" config.create_error_report(78, message, self.usb_info, self.logger, is_blocking=True)
def send_now(self, line): with self.send_now_lock: if self.print_thread and self.print_thread.is_alive(): self.print_thread.send_now_buffer.append(line) else: with self.homing_lock: self.homing_thread.join() while not self.ready_for_command: if self.stop_flag: return if not self.operational_flag: return time.sleep(PrintThread.OK_WAITING_STEP) self.ready_for_command = False if self.connection.send(line): self.analyze_sent_line(line) # we need to wait for processing of current command, to avoid errors in print_thread while not self.ready_for_command: if self.stop_flag: return if not self.operational_flag: return time.sleep(PrintThread.OK_WAITING_STEP) else: self.ready_for_command = True config.create_error_report( "Unable to write to serial port", 250, self.usb_info, self.logger, is_blocking=False)
def send_now(self, line): with self.send_now_lock: if self.print_thread and self.print_thread.is_alive(): self.print_thread.send_now_buffer.append(line) else: with self.homing_lock: self.homing_thread.join() while not self.ready_for_command: if self.stop_flag: return if not self.operational_flag: return time.sleep(PrintThread.OK_WAITING_STEP) self.ready_for_command = False if self.connection.send(line): self.analyze_sent_line(line) # we need to wait for processing of current command, to avoid errors in print_thread while not self.ready_for_command: if self.stop_flag: return if not self.operational_flag: return time.sleep(PrintThread.OK_WAITING_STEP) else: self.ready_for_command = True config.create_error_report("Unable to write to serial port", 250, self.usb_info, self.logger, is_blocking=False)
def execute_server_command(self, server_message): number, command, payload = server_message['number'], server_message[ 'command'], server_message.get('payload') self.logger.info("Executing command number %i : %s" % (number, str(command))) method = getattr(self.printer, command) arguments = [] if payload: arguments.append(payload) if server_message.get('is_link'): arguments.append(True) try: result = method(*arguments) # to reduce needless return True, we assume that when method had return None, that is success result = result or result == None except Exception as e: config.create_error_report( 109, "Error while executing command %s, number %d.\t%s" % (command, number, e.message), self.usb_info, self.logger, is_blocking=False) result = False ack = {"number": number, "result": result} return ack
def start_download(self): self.logger.info("Downloading from " + self.url) self.tmp_file = tempfile.NamedTemporaryFile(mode='wb', delete=False, prefix='3dprinteros-', suffix='.gcode') resume_byte_pos = 0 retry = 0 while retry < self.MAX_RETRIES and not self.base_sender.stop_flag and not self.cancel_flag: if retry: self.logger.warning("Download retry/resume N%d" % retry) self.logger.info("Connecting to " + self.url) resume_header = {'Range': 'bytes=%d-' % resume_byte_pos} try: request = requests.get(self.url, headers = resume_header, stream=True, timeout = self.timeout) except Exception as e: request = None config.create_error_report(65, "Unable to open download link: " + str(e), self.base_sender.usb_info, self.logger, is_blocking=False) else: self.increase_timeout() self.logger.info("Successful connection to " + self.url) download_length = int(request.headers.get('content-length', 0)) if download_length: downloaded_size = self.downloading_loop(request, download_length) resume_byte_pos += downloaded_size self.logger.info("Downloaded %d bytes" % resume_byte_pos) if downloaded_size == download_length: self.tmp_file.close() return self.tmp_file.name finally: if request: request.close() retry += 1 time.sleep(1) self.tmp_file.close()
def check_server_command(self, server_message): if self.last_error: if server_message.get('command'): self.logger.error( "! Server returns command on request containing an error - this is error." ) return { "number": server_message.get('number'), "result": False } error = server_message.get('error') if error: self.logger.warning("@ Error in server message:%s\t%s" % (str(error['code']), error['message'])) command = server_message.get('command') if command: method = getattr(self.printer, command, None) if type(server_message.get('number')) != int: message = "Error in number field of server's message: " + str( server_message) config.create_error_report(41, message, self.logger, is_blocking=False) elif not method: config.create_error_report(40, "Unknown command:'%s' " % str(command), self.usb_info, self.logger, is_blocking=False) else: return self.execute_server_command(server_message)
def pack(self, target, *args, **kwargs): if target == 'user_login': data = { 'login': {'user': args[0], 'password': args[1]}, "platform": sys.platform, 'host_mac': self.MACHINE_ID, "version": version.version } path = self.user_login_path elif target == 'printer_login': data = { 'user_token': args[0], 'printer': args[1], "version": version.version, "data_time": time.ctime(), "camera": config.get_app().camera_controller.get_current_camera_name()} path = self.printer_login_path elif target == 'command': data = { 'printer_token': args[0], 'report': args[1], 'command_ack': args[2] } if not data['command_ack']: data.pop('command_ack') path = self.command_path elif target == 'camera': data = { 'user_token': args[0], 'camera_number': args[1], 'camera_name': args[2], 'file_data': args[3], 'host_mac': self.MACHINE_ID } path = self.camera_path elif target == 'cloudsync': data = { 'user_token': args[0], 'file_data': args[1] } path = self.cloudsync_path else: config.create_error_report(4, 'No such target for packaging: ' + target, None, self.logger, is_blocking=False) data, path = None, None for key, value in kwargs.items(): data[key] = value return path, json.dumps(data)
def connect(self): self.logger.debug("{ Connecting...") fails = 0 while not self.parent.stop_flag: try: if self.HTTPS_MODE: connection = httplib.HTTPSConnection(self.URL, port = 443, timeout = self.timeout) else: connection = httplib.HTTPConnection(self.URL, port = 80, timeout = self.timeout) connection.connect() self.local_ip = connection.sock.getsockname()[0] self.mac = self.get_mac_add_or_serial_number() except Exception as e: config.create_error_report(5, "Error during HTTP connection: " + str(e), self.parent_usb_info, self.logger, is_blocking=False) self.logger.debug("...failed }") self.logger.warning("Warning: connection to %s failed." % self.URL) if self.timeout < self.MAX_TIMEOUT: self.timeout += self.BASE_TIMEOUT time.sleep(1) fails += 1 if fails > self.MAX_FAILS: return else: self.logger.debug("...success }") self.logger.info("Connecting from: %s\t%s" % (self.local_ip, self.mac)) return connection
def unbuffered_gcodes(self, gcodes): # TODO: Add report for not support this config.create_error_report(705, "This printer don't support Gcodes", self.usb_info, self.logger, is_blocking=False) return None
def unpause(self): # FIXME: Its ugly, need move to BirdwingConnector or better MakerBotAPI if self.pause_flag and "resume" in self.available_methods: self.makerbot.unpause_print() self.pause_flag = False else: config.create_error_report(704, "For now, cannot use command resume.", self.usb_info, self.logger, is_blocking=False) return False
def pause(self): # if self.print_thread: # if not self.print_thread.paused: # self.print_thread.send("M25", add_checksum=False) # self.print_thread.paused = True # return True message = "This feature do not supported" config.create_error_report(902, message, self.usb_info, self.logger, is_blocking=False) return False
def cancel(self): # TODO: Not working on Cloud, REPORT ME message = "Cancel is not supported by BOSCH Dremel" config.create_error_report(605, message, self.usb_info, self.logger, is_blocking=False) return False
def load_gcodes(self, gcodes): if self.operational_flag and not self.is_printing(): return self.upload_gcodes_and_print(gcodes) else: config.create_error_report(604, "Printer already printing.", self.usb_info, self.logger, is_blocking=False) return False
def load_json(self, jdata): try: data = json.loads(jdata) except ValueError: config.create_error_report(2, "Received data is not valid json: " + jdata, self.parent_usb_info, self.logger, is_blocking=False) else: if data and type(data) == dict: return data else: config.create_error_report(3, "Error parsing http message, data should be not empty dictionary: " + str(data), self.parent_usb_info, self.logger, is_blocking=False)
def set_groups(self, groups): if type(groups) == list: self.logger.info("Groups are set correctly for %s %s" % (str(self.usb_info), str(groups))) self.groups = groups else: config.create_error_report( 999, "Invalid workgroups format - type must be list: " + str(groups), self.usb_info, self.logger, is_blocking=False)
def send(self, line, add_checksum=True): if add_checksum: line = self.add_line_number_and_checksum(line) # we need to do this before sending to avoid bugs when resent request change line number before +1 self.sender.ready_for_command.clear() if self.sender.connection.send(line): if add_checksum: self.lines_sent += 1 self.sender.analyze_sent_line(line) else: self.sender.ready_for_command.set() config.create_error_report(250, "Unable to write to serial port", self.sender.usb_info, self.logger, is_blocking=False)
def load_gcodes(self, gcode_file): if not self.printing_flag: if not self.makerbot.put_file(gcode_file, self.REMOTE_URL_PATH_FILE): config.create_error_report(701, "Cannot upload file to printer", self.usb_info, self.logger, is_blocking=True) return if not self.makerbot.start_printing_file(self.REMOTE_URL_PATH_FILE): config.create_error_report(702, "Cannot start print", self.usb_info, self.logger, is_blocking=True) return self.logger.info("Success start print") else: return False
def load_gcodes(self, gcodes): self.logger.info("Loading gcodes in ThreadedSender") with self.thread_start_lock: if (self.print_thread and self.print_thread.is_alive()): self.logger.info("Joining printing thread...") self.print_thread.join(timeout=self.PRINT_JOIN_TIMEOUT) if self.print_thread.is_alive(): message = "Can't start print cause already printing" config.create_error_report(260, message, self.usb_info, self.logger, is_blocking=False) return False self.print_thread = SDCardPrintThread(self) self.print_thread.load_gcodes(gcodes) self.print_thread.start() self.logger.info("Print thread started")
def load_gcodes(self, gcodes): self.logger.info("Loading gcodes in ThreadedSender") with self.thread_start_lock: if (self.print_thread and self.print_thread.is_alive()): self.logger.info("Joining printing thread...") self.print_thread.join(timeout=self.PRINT_JOIN_TIMEOUT) if self.print_thread.is_alive(): message = "Can't start print cause already printing" config.create_error_report(260, message, self.usb_info, self.logger, is_blocking=False) return False self.print_thread = PrintThread(self) self.print_thread.load_gcodes(gcodes) self.print_thread.start() self.logger.info("Print thread started")
def reading(self): last_ok_time = time.time() while not self.stop_flag: line = self.connection.recv() if self.parse_printer_answers(line): last_ok_time = time.time() if self.last_gcode_was_blocking_heating and not self.in_heating: # dropping in_heating flag self.last_gcode_was_blocking_heating = False # after ok on next gcode elif not self.in_heating: self.in_heating = self.last_gcode_was_blocking_heating # assuming last ok was for blocking heating if last_ok_time > time.time() + self.OK_TIMEOUT: message = "Warning! Timeout while waiting for ok. Must be printer error." config.create_error_report(251, message, self.usb_info, self.logger, is_blocking=False) last_ok_time = time.time()
def pause(self): if self.print_thread: if not self.print_thread.paused: if self.in_heating: message = "Can't pause during heating." config.create_error_report(254, message, self.usb_info, self.logger, is_blocking=False) return False self.print_thread.paused = True self.was_in_relative_before_pause = self.in_relative_pos_mode if not self.in_relative_pos_mode: self.send_now("G91") self.send_now("G1 Z+%d E-%d" % (self.pause_lift_height, self.pause_extrude_length)) return True return False
def start_main_loop( self ): #TODO cleanup from network and virtual code. main loop code should be short. self.detector = usb_detect.USBDetector() self.network_printers_detector = network_detect.NetworkDetector() self.last_time = 0 while not self.stop_flag: self.updater.timer_check_for_updates() try: self.detected_printers = self.detector.get_printers_list() except Exception: self.logger.exception("USB detector error: ") else: if self.network_detect_flag: self.network_printers = self.network_printers_detector.get_printers( ) self.network_detect_flag = False for printer in self.network_printers: if printer not in self.detected_printers: self.detected_printers.append(printer) if self.virtual_printer_enabled: self.detected_printers.append( self.VIRTUAL_PRINTER_USB_INFO) self.connect_new_printers() for pi in self.printer_interfaces: if pi.usb_info not in self.detected_printers: if not pi.error_state == "error": config.create_error_report( 99, "Printer is no longer detected as USB device.", pi.usb_info, self.logger, is_blocking=True) if not pi.is_alive(): if not pi.stop_flag: self.logger.warning( "Printer interface of %s had crushed" % pi.usb_info) self.logger.info('Removing %s from printer list' % pi.usb_info) self.printer_interfaces.remove(pi) if not self.stop_flag: time.sleep(self.MAIN_LOOP_SLEEP) now = time.time() if self.last_time + self.IDLE_RECORD_TIMEOUT > now: self.last_time = now self.logger.debug( time.strftime("%d %b %Y %H:%M:%S", time.localtime())) self.quit()
def run(self): self.logger.info('Starting downloading') downloaded_filename = self.start_download() if downloaded_filename: with open(downloaded_filename, 'rb') as f: self.base_sender.load_gcodes(f.read()) self.logger.info('Gcodes loaded to memory, deleting temp file') try: os.remove(downloaded_filename) except: pass elif not self.cancel_flag: config.create_error_report(67, "Can't download gcodes", self.base_sender.usb_info, self.logger, is_blocking=False) self.logger.info('Downloading finished')
def check_operational_state(self): if not self.printer or self.stop_flag: pass elif self.printer.stop_flag: pass elif self.printer.is_operational(): #TODO check this operation for thread safety self.last_operational_time = time.time() self.error_state = None self.last_errors = [] elif not self.error_state: message = "Printer is not operational" config.create_error_report(77, message, self.usb_info, self.logger, is_blocking=False) elif self.error_state != "error" and self.last_operational_time + self.READY_TIMEOUT < time.time(): message = "Not operational timeout reached" config.create_error_report(78, message, self.usb_info, self.logger, is_blocking=True)
def connect_to_printer(self): printer_sender = __import__(self.printer_profile['sender']) self.logger.info("Connecting with profile: " + str(self.printer_profile)) try: printer = printer_sender.Sender(self.printer_profile, self.usb_info) except RuntimeError as e: message = "Can't connect to printer %s %s\nReason: %s" %\ (self.printer_profile['name'], str(self.usb_info), e.message) config.create_error_report(119, message, self.usb_info, self.logger, is_blocking=True) except Exception as e: message = "Unexpected error while connecting to %s: %s" % (self.printer_profile['name'], str(e)) config.create_error_report(129, message, self.usb_info, self.logger, is_blocking=True) else: self.logger.info("Successful connection to %s!" % (self.printer_profile['name'])) return printer
def connect(self): self.logger.debug("{ Connecting...") try: if self.HTTPS_MODE: connection = httplib.HTTPSConnection(self.URL, port = 443, timeout = CONNECTION_TIMEOUT) else: connection = httplib.HTTPConnection(self.URL, port = 80, timeout = CONNECTION_TIMEOUT) connection.connect() except Exception as e: config.create_error_report(5, "Error during HTTP connection: " + str(e), self.parent_usb_info, self.logger, is_blocking=False) self.logger.debug("...failed }") self.logger.warning("Warning: connection to %s failed." % self.URL) else: self.logger.debug("...success }") return connection
def send(self, line, add_checksum=True, force_line_number=None): if add_checksum and not self.no_checksums: if not force_line_number is None: line = self.add_line_number_and_checksum(line, force_line_number=force_line_number) else: line = self.add_line_number_and_checksum(line) # we need to do this before sending to avoid bugs when resent request change line number before +1 self.sender.ready_for_command = False if add_checksum and not force_line_number: self.lines_sent += 1 if self.sender.connection.send(line): self.sender.analyze_sent_line(line) else: self.sender.ready_for_command = True config.create_error_report("Unable to write to serial port", 250, self.sender.usb_info, self.logger, is_blocking=False)
def connect_to_server(self): #TODO REMOVE THIS UGLY METHOD - connection must server command, like gcodes or pause self.logger.info("Connecting to server with printer: %s" % str(self.usb_info)) self.http_client = http_client.HTTPClient(self, keep_connection_flag=True) while not self.stop_flag: external_errors = self.get_my_errors() if filter(lambda error: error['is_blocking'], external_errors): self.stop_flag = True return False message = ['printer_login', self.user_token, self.usb_info] kw_message = {} if self.printer_type_selection_request: kw_message['select_printer_type'] = self.printer_type_selection_request self.logger.debug('Printer login request:\n%s\n%s ' % (str(message), str(kw_message))) answer = self.http_client.pack_and_send(*message, **kw_message) if answer: error = answer.get('error') self.printer_name = answer.get('name', '') if error: self.logger.warning("Error while login %s:" % str((self.user_token, self.usb_info))) self.logger.warning(str(error['code']) + " " + error["message"]) if str(error['code']) == '8': self.show_printer_type_selector = True time.sleep(1) continue else: config.create_error_report(26, "Server had returned error: %s" % str(error)) return False elif answer.get('printer_profile') == "": config.create_error_report(62, "Server return message with empty printer_profile field: %s" % str(error)) else: groups = answer.get('current_groups', []) self.set_groups(groups) self.printer_type_selection_request = None self.show_printer_type_selector = False self.printer_rename_request = False self.logger.info('Successfully connected to server.') self.printer_token = answer['printer_token'] self.logger.info('Received answer: ' + str(answer)) self.printer_profile = json.loads(answer["printer_profile"]) custom_timeout = self.printer_profile.get("operational_timeout", None) if custom_timeout: self.READY_TIMEOUT = custom_timeout self.logger.debug('Setting profile: ' + str(self.printer_profile)) return True else: self.logger.warning("Error on printer login. No connection or answer from server.") time.sleep(0.1)
def cancel(self): if self.cancel_download(): return self.stop_flag = True if self.print_thread: self.print_thread.cancel() self.print_thread.join() self.read_thread.join() self.temperature_request_thread.join() self.reset() self.stop_flag = False try: self.init() self.logger.info("Successful cancel") except RuntimeError: message = "Can't reconnect to printer after cancel." config.create_error_report(255, message, self.usb_info, self.logger, is_blocking=True)
def update(self): if self.update_flag: self.logger.info('Updating client...') update_file_name = config.get_settings()['update']['update_file_name'] try: urllib.urlretrieve(config.get_settings()['update']['update_file_url'] + update_file_name, update_file_name) except Exception as e: error_message = 'Update failed!\nReason: error while downloading.\nDetails: ' + str(e) config.create_error_report(0, error_message, None, self.logger, is_blocking=True) return error_message else: error = self.extract_update(update_file_name) if error: return error self.logger.info('...client successfully updated!') self.update_flag = False log.send_logs() log.clear_logs()
def downloading_loop(self, request, download_length): # Taking +1 byte with each chunk to compensate file length tail less than 100 bytes when dividing by 100 percent_length = download_length / 100 + 1 total_size = 0 try: for chunk in request.iter_content(percent_length): if self.cancel_flag or self.base_sender.stop_flag: self.logger.info('Download canceled') break self.tmp_file.write(chunk) self.percent += 1 total_size += len(chunk) self.logger.info('File downloading : %d%%' % self.percent) except Exception as e: config.create_error_report(66, 'Error while downloading: ' + str(e.message), self.base_sender.usb_info, self.logger, is_blocking=False) finally: return total_size
def close(self): self.logger.info("Makerbot sender is closing...") self.stop_flag = True if threading.current_thread() != self.sending_thread: self.sending_thread.join(10) if self.sending_thread.isAlive(): config.create_error_report(301, "Failed to join printing thread in makerbot_printer", self.usb_info, self.logger, is_blocking=True) if self.parser: if self.parser.s3g: try: self.parser.s3g.abort_immediately() except Exception: pass time.sleep(0.1) self.parser.s3g.close() self.is_running = False self.logger.info("...done closing makerbot sender.")
def log_strange_acks(self, line): if self.print_thread: if "Done printing file" in line: self.print_thread.print_thread_flag = False self.print_thread.lines_sent = self.print_thread.total_gcodes elif "SD printing" in line: progress_match = self.progress_re.match(line) if progress_match: self.print_thread.lines_sent = int(progress_match.group(1)) self.print_thread.total_gcodes = int(progress_match.group(2)) if self.print_thread.total_gcodes > 0: if self.print_thread.lines_sent >= self.print_thread.total_gcodes: self.print_thread.print_thread_flag = False elif "error" in line or "failed" in line: self.operational_flag = False config.create_error_report(900, line, self.usb_info, self.logger, is_blocking=True) else: self.logger.warning("Received strange answer: " + line.strip())
def parse_printer_answers(self, line): if line is None: # None means error reading from printer, but "" is ok self.operational_flag = False time.sleep(self.PAUSE_ON_ERROR_READING_PORT) elif not line or "wait" in line: if self.extra_oks: self.extra_oks -= 1 self.ready_for_command.set() return # return is needed here for faster the parsing elif self.is_ok(line): self.operational_flag = True self.check_temperature_and_position(line) if self.ready_for_command.is_set(): self.extra_oks += 1 self.logger.info( "Warning: double ok was received. Extra oks counter is now: %d" % self.extra_oks) self.ready_for_command.set() return self.last_line_sent != self.GET_TEMP_GCODE # M105 should not be affect anti-stuck code mechanism elif line[0] == "T" or (len(line) > 1 and line[1] == "T"): self.parse_waiting_temperature_updates(line) self.operational_flag = True elif self.check_for_resend_requests(line): self.logger.debug(line) self.logger.info("Last_line: " + self.last_line_sent) self.operational_flag = True self.ready_for_command.set() elif line.startswith('Error'): self.logger.debug(line) self.logger.info("Last_line: " + self.last_line_sent) if not ("checksum" in line or "Checksum" in line or "expected line" in line or "Line Number is not Last Line Number+1" in line or "Format error" in line): is_blocking = self.BOARD_RESET_GCODE in line or "disabling all for safety!" in line self.operational_flag = False config.create_error_report(201, line, self.usb_info, self.logger, is_blocking=is_blocking) elif line.startswith('DEBUG'): self.logger.info(line) else: self.log_strange_acks(line)
def start_download(self): self.logger.info("Downloading from " + self.url) self.tmp_file = tempfile.NamedTemporaryFile(mode='wb', delete=False, prefix='3dprinteros-', suffix='.gcode') resume_byte_pos = 0 retry = 0 while retry < self.MAX_RETRIES and not self.base_sender.stop_flag and not self.cancel_flag: if retry: self.logger.warning("Download retry/resume N%d" % retry) self.logger.info("Connecting to " + self.url) resume_header = {'Range': 'bytes=%d-' % resume_byte_pos} try: request = requests.get(self.url, headers=resume_header, stream=True, timeout=self.timeout) except Exception as e: request = None config.create_error_report(65, "Unable to open download link: " + str(e), self.base_sender.usb_info, self.logger, is_blocking=False) else: self.increase_timeout() self.logger.info("Successful connection to " + self.url) download_length = int(request.headers.get('content-length', 0)) if download_length: downloaded_size = self.downloading_loop( request, download_length) resume_byte_pos += downloaded_size self.logger.info("Downloaded %d bytes" % resume_byte_pos) if downloaded_size == download_length: self.tmp_file.close() return self.tmp_file.name finally: if request: request.close() retry += 1 time.sleep(1) self.tmp_file.close()
def execute_server_command(self, server_message): number, command, payload = server_message['number'], server_message['command'], server_message.get('payload') self.logger.info("Executing command number %i : %s" % (number, str(command))) method = getattr(self.printer, command) arguments = [] if payload: arguments.append(payload) if server_message.get('is_link'): arguments.append(True) try: result = method(*arguments) # to reduce needless return True, we assume that when method had return None, that is success result = result or result == None except Exception as e: config.create_error_report(109, "Error while executing command %s, number %d.\t%s" % (command, number, e.message), self.usb_info, self.logger, is_blocking=False) result = False ack = { "number": number, "result": result } return ack
def check_server_command(self, server_message): if self.last_error: if server_message.get('command'): self.logger.error("! Server returns command on request containing an error - this is error.") return { "number": server_message.get('number'), "result": False } error = server_message.get('error') if error: self.logger.warning("@ Error in server message:%s\t%s" % (str(error['code']), error['message'])) command = server_message.get('command') if command: method = getattr(self.printer, command, None) if type(server_message.get('number')) != int: message = "Error in number field of server's message: " + str(server_message) config.create_error_report(41, message, self.logger, is_blocking=False) elif not method: config.create_error_report(40, "Unknown command:'%s' " % str(command), self.usb_info, self.logger, is_blocking=False) else: return self.execute_server_command(server_message)
def execute(self, command): buffer_overflow_counter = 0 retry_count = 0 while not self.stop_flag: if buffer_overflow_counter > self.BUFFER_OVERFLOWS_BETWEEN_STATE_UPDATE: self.logger.info('Makerbot BufferOverflow on ' + text) buffer_overflow_counter = 0 self.read_state() try: command_is_gcode = isinstance(command, str) self.execution_lock.acquire() if command_is_gcode: if self.cancel_flag: self.cancel_flag = False break text = command self.printing_flag = True self.parser.execute_line(command) self.set_target_temps(command) #self.logger.debug("Executing: " + command) result = None else: text = command.__name__ result = command() except (makerbot_driver.BufferOverflowError): buffer_overflow_counter += 1 time.sleep(self.BUFFER_OVERFLOW_WAIT) except serial.serialutil.SerialException: self.logger.warning("Makerbot is retrying %i %s" % (retry_count, text)) retry_count += 1 if retry_count > self.MAX_RETRY_BEFORE_ERROR: config.create_error_report(302, "Makerbot can't continue because max retry of %s" % text, self.usb_info, self.logger, is_blocking=True) self.close() except Exception as e: config.create_error_report(303, "Makerbot can't continue because of: %s %s" % (str(e), e.message), self.usb_info, self.logger, is_blocking=True) self.close() else: return result finally: self.execution_lock.release()
def send(self, line, add_checksum=True, force_line_number=None): if add_checksum and not self.no_checksums: if not force_line_number is None: line = self.add_line_number_and_checksum( line, force_line_number=force_line_number) else: line = self.add_line_number_and_checksum(line) # we need to do this before sending to avoid bugs when resent request change line number before +1 self.sender.ready_for_command = False if add_checksum and not force_line_number: self.lines_sent += 1 if self.sender.connection.send(line): self.sender.analyze_sent_line(line) else: self.sender.ready_for_command = True config.create_error_report("Unable to write to serial port", 250, self.sender.usb_info, self.logger, is_blocking=False)
def pause(self): if self.print_thread: if not self.print_thread.paused: if self.in_heating: message = "Can't pause during heating." config.create_error_report(254, message, self.usb_info, self.logger, is_blocking=False) return False self.print_thread.paused = True self.was_in_relative_before_pause = self.in_relative_pos_mode if not self.in_relative_pos_mode: self.send_now("G91") self.send_now( "G1 Z+%d E-%d" % (self.pause_lift_height, self.pause_extrude_length)) return True return False
def send(self, path, data): while True: if not self.connection: self.connection = self.connect() if self.connection: answer = self.request("POST", self.connection, path, data) if not self.keep_connection_flag: self.connection.close() self.connection = None if answer: self.fails = 0 return self.load_json(answer) self.fails += 1 time.sleep(1) if self.fails > self.MAX_HTTP_FAILS: self.fails = 0 if self.connection: self.connection.close() self.connection = None config.create_error_report(9, 'HTTP error: max request retry.', None, self.logger, is_blocking=False) break