def test_convert_pause_triggers(self): configured_triggers = [ dict(regex="pause1", type="enable"), dict(regex="pause2", type="enable"), dict(regex="resume", type="disable"), dict(regex="toggle", type="toggle"), dict(type="enable"), dict(regex="regex"), dict(regex="regex", type="unknown") ] from octoprint.util import comm trigger_matchers = comm.convert_pause_triggers(configured_triggers) self.assertIsNotNone(trigger_matchers) self.assertIn("enable", trigger_matchers) self.assertEquals("(pause1)|(pause2)", trigger_matchers["enable"].pattern) self.assertIn("disable", trigger_matchers) self.assertEquals("(resume)", trigger_matchers["disable"].pattern) self.assertIn("toggle", trigger_matchers) self.assertEquals("(toggle)", trigger_matchers["toggle"].pattern) self.assertNotIn("unknown", trigger_matchers)
def test_convert_pause_triggers(self): configured_triggers = [ dict(regex="pause1", type="enable"), dict(regex="pause2", type="enable"), dict(regex="resume", type="disable"), dict(regex="toggle", type="toggle"), dict(type="enable"), dict(regex="regex"), dict(regex="regex", type="unknown") ] from octoprint.util import comm trigger_matchers = comm.convert_pause_triggers(configured_triggers) self.assertIsNotNone(trigger_matchers) self.assertIn("enable", trigger_matchers) self.assertEqual("(pause1)|(pause2)", trigger_matchers["enable"].pattern) self.assertIn("disable", trigger_matchers) self.assertEqual("(resume)", trigger_matchers["disable"].pattern) self.assertIn("toggle", trigger_matchers) self.assertEqual("(toggle)", trigger_matchers["toggle"].pattern) self.assertNotIn("unknown", trigger_matchers)
def _monitor(self): """ Monitor thread of responses from the commands sent to the printer :return: """ feedback_controls, feedback_matcher = comm.convert_feedback_controls(settings().get(["controls"])) feedback_errors = [] pause_triggers = comm.convert_pause_triggers(settings().get(["printerParameters", "pauseTriggers"])) #exits if no connection is active if not self._beeConn.isConnected(): return startSeen = False supportWait = settings().getBoolean(["feature", "supportWait"]) while self._monitoring_active: try: line = self._getResponse() if line is None: continue ##~~ debugging output handling if line.startswith("//"): debugging_output = line[2:].strip() if debugging_output.startswith("action:"): action_command = debugging_output[len("action:"):].strip() if action_command == "pause": self._log("Pausing on request of the printer...") self.setPause(True) elif action_command == "resume": self._log("Resuming on request of the printer...") self.setPause(False) elif action_command == "disconnect": self._log("Disconnecting on request of the printer...") self._callback.on_comm_force_disconnect() else: for hook in self._printer_action_hooks: try: self._printer_action_hooks[hook](self, line, action_command) except: self._logger.exception("Error while calling hook {} with action command {}".format(self._printer_action_hooks[hook], action_command)) continue else: continue ##~~ Error handling line = self._handleErrors(line) ##~~ process oks if line.strip().startswith("ok") or (self.isPrinting() and supportWait and line.strip().startswith("wait")): self._clear_to_send.set() self._long_running_command = False ##~~ Temperature processing if ' T:' in line or line.startswith('T:') or ' T0:' in line or line.startswith('T0:') \ or ' B:' in line or line.startswith('B:'): self._processTemperatures(line) self._callback.on_comm_temperature_update(self._temp, self._bedTemp) ##~~ SD Card handling elif 'SD init fail' in line or 'volume.init failed' in line or 'openRoot failed' in line: self._sdAvailable = False self._sdFiles = [] self._callback.on_comm_sd_state_change(self._sdAvailable) elif 'Not SD printing' in line: if self.isSdFileSelected() and self.isPrinting(): # something went wrong, printer is reporting that we actually are not printing right now... self._sdFilePos = 0 self._changeState(self.STATE_OPERATIONAL) elif 'SD card ok' in line and not self._sdAvailable: self._sdAvailable = True self.refreshSdFiles() self._callback.on_comm_sd_state_change(self._sdAvailable) elif 'Begin file list' in line: self._sdFiles = [] self._sdFileList = True elif 'End file list' in line: self._sdFileList = False self._callback.on_comm_sd_files(self._sdFiles) elif 'SD printing byte' in line and self.isSdPrinting(): # answer to M27, at least on Marlin, Repetier and Sprinter: "SD printing byte %d/%d" match = regex_sdPrintingByte.search(line) self._currentFile.setFilepos(int(match.group(1))) self._callback.on_comm_progress() elif 'File opened' in line and not self._ignore_select: # answer to M23, at least on Marlin, Repetier and Sprinter: "File opened:%s Size:%d" match = regex_sdFileOpened.search(line) if self._sdFileToSelect: name = self._sdFileToSelect self._sdFileToSelect = None else: name = match.group(1) self._currentFile = comm.PrintingSdFileInformation(name, int(match.group(2))) elif 'File selected' in line: if self._ignore_select: self._ignore_select = False elif self._currentFile is not None: # final answer to M23, at least on Marlin, Repetier and Sprinter: "File selected" self._callback.on_comm_file_selected(self._currentFile.getFilename(), self._currentFile.getFilesize(), True) eventManager().fire(Events.FILE_SELECTED, { "file": self._currentFile.getFilename(), "origin": self._currentFile.getFileLocation() }) elif 'Writing to file' in line: # answer to M28, at least on Marlin, Repetier and Sprinter: "Writing to file: %s" self._changeState(self.STATE_PRINTING) self._clear_to_send.set() line = "ok" elif 'Done saving file' in line: self.refreshSdFiles() elif 'File deleted' in line and line.strip().endswith("ok"): # buggy Marlin version that doesn't send a proper \r after the "File deleted" statement, fixed in # current versions self._clear_to_send.set() ##~~ Message handling elif line.strip() != '' \ and line.strip() != 'ok' and not line.startswith("wait") \ and not line.startswith('Resend:') \ and line != 'echo:Unknown command:""\n' \ and self.isOperational(): self._callback.on_comm_message(line) ##~~ Parsing for feedback commands if feedback_controls and feedback_matcher and not "_all" in feedback_errors: try: self._process_registered_message(line, feedback_matcher, feedback_controls, feedback_errors) except: # something went wrong while feedback matching self._logger.exception("Error while trying to apply feedback control matching, disabling it") feedback_errors.append("_all") ##~~ Parsing for pause triggers if pause_triggers and not self.isStreaming(): if "enable" in pause_triggers.keys() and pause_triggers["enable"].search(line) is not None: self.setPause(True) elif "disable" in pause_triggers.keys() and pause_triggers["disable"].search(line) is not None: self.setPause(False) elif "toggle" in pause_triggers.keys() and pause_triggers["toggle"].search(line) is not None: self.setPause(not self.isPaused()) self.setPause(not self.isPaused()) ### Connection attempt elif self._state == self.STATE_CONNECTING: if "start" in line and not startSeen: startSeen = True self._sendCommand("M110") self._clear_to_send.set() elif "ok" in line: self._onConnected() elif time.time() > self._timeout: self.close() ### Operational elif self._state == self.STATE_OPERATIONAL or self._state == self.STATE_PAUSED: if "ok" in line: # if we still have commands to process, process them if self._resendDelta is not None: self._resendNextCommand() elif self._sendFromQueue(): pass # resend -> start resend procedure from requested line elif line.lower().startswith("resend") or line.lower().startswith("rs"): self._handleResendRequest(line) except Exception as ex: self._logger.exception("Something crashed inside the USB connection.") errorMsg = "See octoprint.log for details" self._log(ex.message) self._errorValue = errorMsg self._changeState(self.STATE_ERROR) eventManager().fire(Events.ERROR, {"error": self.getErrorString()}) self._log("Connection closed, closing down monitor")