Пример #1
0
	def _waitForHeatup(self, heater, only_wait_if_higher):
		delta = 1
		delay = 1
		last_busy = monotonic_time()

		self._heatingUp = True
		try:
			if heater.startswith("tool"):
				toolNum = int(heater[len("tool"):])
				test = lambda: self.temp[toolNum] < self.targetTemp[toolNum] - delta or (not only_wait_if_higher and self.temp[toolNum] > self.targetTemp[toolNum] + delta)
				output = lambda: "T:%0.2f" % self.temp[toolNum]
			elif heater == "bed":
				test = lambda: self.bedTemp < self.bedTargetTemp - delta or (not only_wait_if_higher and self.bedTemp > self.bedTargetTemp + delta)
				output = lambda: "B:%0.2f" % self.bedTemp
			elif heater == "chamber":
				test = lambda: self.chamberTemp < self.chamberTargetTemp - delta or (not only_wait_if_higher and self.chamberTemp > self.chamberTargetTemp + delta)
				output = lambda: "C:%0.2f" % self.chamberTemp
			else:
				return

			while not self._killed and self._heatingUp and test():
				self._simulateTemps(delta=delta)
				self._output(output())
				if self._sendBusy and monotonic_time() - last_busy >= self._busyInterval:
					self._output("echo:busy: processing")
					last_busy = monotonic_time()
				time.sleep(delay)
		except AttributeError:
			if self.outgoing is not None:
				raise
		finally:
			self._heatingUp = False
Пример #2
0
	def _simulateTemps(self, delta=0.5):
		timeDiff = self.lastTempAt - monotonic_time()
		self.lastTempAt = monotonic_time()

		def simulate(actual, target, ambient):
			if target > 0 and abs(actual - target) > delta:
				goal = target
				factor = 10
			elif not target and abs(actual - ambient) > delta:
				goal = ambient
				factor = 2
			else:
				return actual

			old = actual
			actual += math.copysign(timeDiff * factor, goal - actual)

			if math.copysign(1, goal - old) != math.copysign(1, goal - actual):
				actual = goal

			return actual

		for i in range(len(self.temp)):
			if i in self.pinnedExtruders:
				self.temp[i] = self.pinnedExtruders[i]
				continue
			self.temp[i] = simulate(self.temp[i], self.targetTemp[i], self._ambient_temperature)
		self.bedTemp = simulate(self.bedTemp, self.bedTargetTemp, self._ambient_temperature)
		self.chamberTemp = simulate(self.chamberTemp, self.chamberTargetTemp, self._ambient_temperature)
Пример #3
0
	def _analyze(self, entry, high_priority=False):
		path = entry.absolute_path
		if path is None or not os.path.exists(path):
			return

		self._current = entry
		self._current_highprio = high_priority
		self._current_progress = 0

		try:
			start_time = monotonic_time()
			self._logger.info("Starting analysis of {}".format(entry))
			eventManager().fire(Events.METADATA_ANALYSIS_STARTED, {"name": entry.name,
			                                                       "path": entry.path,
			                                                       "origin": entry.location,
			                                                       "type": entry.type,

			                                                       # TODO deprecated, remove in 1.4.0
			                                                       "file": entry.path})
			try:
				result = self._do_analysis(high_priority=high_priority)
			except TypeError:
				result = self._do_analysis()
			self._logger.info("Analysis of entry {} finished, needed {:.2f}s".format(entry, monotonic_time() - start_time))
			self._finished_callback(self._current, result)
		finally:
			self._current = None
			self._current_progress = None
Пример #4
0
    def _analyze(self, entry, high_priority=False):
        path = entry.absolute_path
        if path is None or not os.path.exists(path):
            return

        self._current = entry
        self._current_highprio = high_priority
        self._current_progress = 0

        try:
            start_time = monotonic_time()
            self._logger.info("Starting analysis of {}".format(entry))
            eventManager().fire(
                Events.METADATA_ANALYSIS_STARTED,
                {
                    "name": entry.name,
                    "path": entry.path,
                    "origin": entry.location,
                    "type": entry.type,
                },
            )
            try:
                result = self._do_analysis(high_priority=high_priority)
            except TypeError:
                result = self._do_analysis()
            self._logger.info(
                "Analysis of entry {} finished, needed {:.2f}s".format(
                    entry, monotonic_time() - start_time
                )
            )
            self._finished_callback(self._current, result)
        finally:
            self._current = None
            self._current_progress = None
Пример #5
0
    def __init__(self, user):
        wrapt.ObjectProxy.__init__(self, user)

        self._self_session = "".join('%02X' % z
                                     for z in bytes(uuid.uuid4().bytes))
        self._self_created = monotonic_time()
        self._self_touched = monotonic_time()
Пример #6
0
	def put(self, item, block=True, timeout=None, partial=False):
		self.not_full.acquire()

		try:
			if not self._will_it_fit(item) and partial:
				space_left = self.maxsize - self._qsize()
				if space_left:
					item = item[:space_left]

			if not block:
				if not self._will_it_fit(item):
					raise queue.Full
			elif timeout is None:
				while not self._will_it_fit(item):
					self.not_full.wait()
			elif timeout < 0:
				raise ValueError("'timeout' must be a positive number")
			else:
				endtime = monotonic_time() + timeout
				while not self._will_it_fit(item):
					remaining = endtime - monotonic_time()
					if remaining <= 0.0:
						raise queue.Full
					self.not_full.wait(remaining)

			self._put(item)
			self.unfinished_tasks += 1
			self.not_empty.notify()

			return self._len(item)
		finally:
			self.not_full.release()
Пример #7
0
def perform_update(target, check, target_version, log_cb=None, online=True):
	duration = check.get("duration", 30)

	now = monotonic_time()
	end = now + duration
	while now < end:
		log_cb(["{}s left...".format(end - now)], prefix=">", stream="output")
		time.sleep(5)
		now = monotonic_time()
Пример #8
0
def perform_update(target, check, target_version, log_cb=None, online=True):
	duration = check.get("duration", 30)

	now = monotonic_time()
	end = now + duration
	while now < end:
		log_cb(["{}s left...".format(end - now)], prefix=">", stream="output")
		time.sleep(5)
		now = monotonic_time()
Пример #9
0
 def evaluate_timeout(self):
     if self._start_time is None:
         self._start_time = monotonic_time()
     else:
         if monotonic_time() > self._start_time + self.ACTIVE_TIMEOUT:
             # timeout ran out, this is now inactive
             self._active = False
             logging.getLogger(__name__).info(
                 "Deactivated {} due to timeout after {}s".format(
                     __name__, self.ACTIVE_TIMEOUT))
Пример #10
0
	def _gcode_G33(self, data):
		self._send("G33 Auto Calibrate")
		self._send("Will take ~60s")
		timeout = 60

		if self._sendBusy and self._busyInterval > 0:
			until = monotonic_time() + timeout
			while monotonic_time() < until:
				time.sleep(self._busyInterval)
				self._send("busy:processing")
		else:
			time.sleep(timeout)
Пример #11
0
def gcode_command(path, speedx, speedy, speedz, offset, maxt, throttle,
                  throttle_lines, g90_extruder, progress):
    """Runs a GCODE file analysis."""

    import time
    import yaml
    from octoprint.util import monotonic_time
    from octoprint.util.gcodeInterpreter import gcode

    throttle_callback = None
    if throttle:

        def throttle_callback(filePos, readBytes):
            if filePos % throttle_lines == 0:
                # only apply throttle every $throttle_lines lines
                time.sleep(throttle)

    offsets = offset
    if offsets is None:
        offsets = []
    elif isinstance(offset, tuple):
        offsets = list(offsets)
    offsets = [(0, 0)] + offsets
    if len(offsets) < maxt:
        offsets += [(0, 0)] * (maxt - len(offsets))

    start_time = monotonic_time()

    progress_callback = None
    if progress:

        def progress_callback(percentage):
            click.echo("PROGRESS:{}".format(percentage))

    interpreter = gcode(progress_callback=progress_callback)

    interpreter.load(path,
                     speedx=speedx,
                     speedy=speedy,
                     offsets=offsets,
                     throttle=throttle_callback,
                     max_extruders=maxt,
                     g90_extruder=g90_extruder)

    click.echo("DONE:{}s".format(monotonic_time() - start_time))
    click.echo("RESULTS:")
    click.echo(
        yaml.safe_dump(interpreter.get_result(),
                       default_flow_style=False,
                       indent=4,
                       allow_unicode=True))
Пример #12
0
	def _cleanup_sessions(self):
		for session, user in list(self._session_users_by_session.items()):
			if not isinstance(user, SessionUser):
				continue
			if user.created + (24 * 60 * 60) < monotonic_time():
				self._logger.info("Cleaning up user session {} for user {}".format(session, user.get_id()))
				self.logout_user(user, stale=True)
Пример #13
0
 def __init__(self, width, height, _printer):
     super().__init__(width, height)
     self._printer = _printer
     self.press_time = monotonic_time()
     self.expired = False
     self.timer = threading.Timer(10, self.timer_expired)
     self.timer.start()
Пример #14
0
    def _track_ping(self):
        if not self._settings.get_boolean(["enabled"]):
            return

        uptime = int(monotonic_time() - self._startup_time)
        printer_state = self._printer.get_state_id()
        self._track("ping", octoprint_uptime=uptime, printer_state=printer_state)
Пример #15
0
	def _gcode_G4(self, data):
		matchS = re.search('S([0-9]+)', data)
		matchP = re.search('P([0-9]+)', data)

		_timeout = 0
		if matchP:
			_timeout = float(matchP.group(1)) / 1000.0
		elif matchS:
			_timeout = float(matchS.group(1))

		if self._sendBusy and self._busyInterval > 0:
			until = monotonic_time() + _timeout
			while monotonic_time() < until:
				time.sleep(self._busyInterval)
				self._send("busy:processing")
		else:
			time.sleep(_timeout)
Пример #16
0
    def handle_button(self, label):
        if label == 'cancel':
            if self.expired or (monotonic_time() - self.press_time) < 1.0:
                return {'IGNORE'}

            self._printer.cancel_print()

        self.expired = True
        return {'BACK'}
Пример #17
0
	def _remove_stale_pending(self):
		with self._pending_lock:
			cutoff = monotonic_time() - CUTOFF_TIME
			len_before = len(self._pending_decisions)
			self._pending_decisions = filter(lambda x: x.created >= cutoff,
			                                 self._pending_decisions)
			len_after = len(self._pending_decisions)
			if len_after < len_before:
				self._logger.info("Deleted {} stale pending authorization requests".format(len_before - len_after))
Пример #18
0
	def __init__(self, user):
		wrapt.ObjectProxy.__init__(self, user)

		import string
		import random
		import time
		chars = string.ascii_uppercase + string.ascii_lowercase + string.digits
		self._self_session = "".join(random.choice(chars) for _ in range(10))
		self._self_created = monotonic_time()
Пример #19
0
    def __init__(self, user):
        wrapt.ObjectProxy.__init__(self, user)

        import string
        import random
        import time
        chars = string.ascii_uppercase + string.ascii_lowercase + string.digits
        self._self_session = "".join(random.choice(chars) for _ in range(10))
        self._self_created = monotonic_time()
Пример #20
0
	def __init__(self, app_id, app_token, user_id, user_token, timeout_callback=None):
		self.app_id = app_id
		self.app_token = app_token
		self.user_id = user_id
		self.user_token = user_token
		self.created = monotonic_time()

		if callable(timeout_callback):
			self.poll_timeout = ResettableTimer(POLL_TIMEOUT, timeout_callback, [user_token])
			self.poll_timeout.start()
Пример #21
0
 def _remove_stale_pending(self):
     with self._pending_lock:
         cutoff = monotonic_time() - CUTOFF_TIME
         len_before = len(self._pending_decisions)
         self._pending_decisions = list(
             filter(lambda x: x.created >= cutoff, self._pending_decisions))
         len_after = len(self._pending_decisions)
         if len_after < len_before:
             self._logger.info(
                 "Deleted {} stale pending authorization requests".format(
                     len_before - len_after))
Пример #22
0
	def __init__(self):
		self._environment = None
		self._throttle_state = None
		self._helpers_get_throttle_state = None
		self._printer_connection_parameters = None
		self._url = None
		self._ping_worker = None
		self._executor = concurrent.futures.ThreadPoolExecutor(max_workers=1)

		self._record_next_firmware_info = False

		self._startup_time = monotonic_time()
Пример #23
0
    def __init__(self):
        self._environment = None
        self._throttle_state = None
        self._helpers_get_throttle_state = None
        self._printer_connection_parameters = None
        self._url = None
        self._ping_worker = None
        self._executor = concurrent.futures.ThreadPoolExecutor(max_workers=1)

        self._record_next_firmware_info = False

        self._startup_time = monotonic_time()
Пример #24
0
    def __init__(self, app_id, app_token, user_id, user_token, timeout_callback=None):
        self.app_id = app_id
        self.app_token = app_token
        self.user_id = user_id
        self.user_token = user_token
        self.created = monotonic_time()

        if callable(timeout_callback):
            self.poll_timeout = ResettableTimer(
                POLL_TIMEOUT, timeout_callback, [user_token]
            )
            self.poll_timeout.start()
Пример #25
0
    def _get_channel_data_from_network(self, key, config):
        """Fetch channel feed from network."""

        import requests

        url = config["url"]
        try:
            start = monotonic_time()
            r = requests.get(url, timeout=30)
            r.raise_for_status()
            self._logger.info("Loaded channel {} from {} in {:.2}s".format(
                key, config["url"],
                monotonic_time() - start))
        except Exception:
            self._logger.exception("Could not fetch channel {} from {}".format(
                key, config["url"]))
            return None

        response = r.text
        channel_path = self._get_channel_cache_path(key)
        with io.open(channel_path, mode="wt", encoding="utf-8") as f:
            f.write(response)
        return feedparser.parse(response)
Пример #26
0
	def _on_z_change(self, event, payload):
		# check if height difference equals z-hop, if so don't take a picture
		if self._retraction_zhop != 0 and payload["old"] is not None and payload["new"] is not None:
			diff = round(abs(payload["new"] - payload["old"]), 3)
			zhop = round(self._retraction_zhop, 3)
			if diff == zhop:
				return

		# check if last picture has been less than min_delay ago, if so don't take a picture (anti vase mode...)
		now = monotonic_time()
		if self._min_delay and self._last_snapshot and self._last_snapshot + self._min_delay > now:
			self._logger.debug("Rate limited z-change, not taking a snapshot")
			return

		self.capture_image()
		self._last_snapshot = now
Пример #27
0
    def _on_z_change(self, event, payload):
        # check if height difference equals z-hop, if so don't take a picture
        if self._retraction_zhop != 0 and payload[
                "old"] is not None and payload["new"] is not None:
            diff = round(abs(payload["new"] - payload["old"]), 3)
            zhop = round(self._retraction_zhop, 3)
            if diff == zhop:
                return

        # check if last picture has been less than min_delay ago, if so don't take a picture (anti vase mode...)
        now = monotonic_time()
        if self._min_delay and self._last_snapshot and self._last_snapshot + self._min_delay > now:
            self._logger.debug("Rate limited z-change, not taking a snapshot")
            return

        self.capture_image()
        self._last_snapshot = now
Пример #28
0
	def _get_channel_data_from_network(self, key, config):
		"""Fetch channel feed from network."""

		import requests

		url = config["url"]
		try:
			start = monotonic_time()
			r = requests.get(url, timeout=30)
			r.raise_for_status()
			self._logger.info(u"Loaded channel {} from {} in {:.2}s".format(key, config["url"], monotonic_time() - start))
		except Exception as e:
			self._logger.exception(
				u"Could not fetch channel {} from {}: {}".format(key, config["url"], str(e)))
			return None

		response = r.text
		channel_path = self._get_channel_cache_path(key)
		with codecs.open(channel_path, mode="w", encoding="utf-8") as f:
			f.write(response)
		return feedparser.parse(response)
Пример #29
0
	def _processIncoming(self):
		next_wait_timeout = monotonic_time() + self._waitInterval
		buf = ""
		while self.incoming is not None and not self._killed:
			self._simulateTemps()

			if self._heatingUp:
				time.sleep(1)
				continue

			try:
				data = self.incoming.get(timeout=0.01)
				self.incoming.task_done()
			except queue.Empty:
				if self._sendWait and monotonic_time() > next_wait_timeout:
					self._send("wait")
					next_wait_timeout = monotonic_time() + self._waitInterval
				continue

			buf += data
			if "\n" in buf:
				data = buf[:buf.find("\n") + 1]
				buf = buf[buf.find("\n") + 1:]
			else:
				continue

			next_wait_timeout = monotonic_time() + self._waitInterval

			if data is None:
				continue

			if self._dont_answer:
				self._dont_answer = False
				continue

			data = to_unicode(data.strip(), errors="replace")

			# strip checksum
			if "*" in data:
				checksum = int(data[data.rfind("*") + 1:])
				data = data[:data.rfind("*")]
				if not checksum == self._calculate_checksum(data):
					self._triggerResend(expected=self.currentLine + 1)
					continue

				self.currentLine += 1
			elif settings().getBoolean(["devel", "virtualPrinter", "forceChecksum"]):
				self._send(self._error("checksum_missing"))
				continue

			# track N = N + 1
			if data.startswith("N") and "M110" in data:
				linenumber = int(re.search("N([0-9]+)", data).group(1))
				self.lastN = linenumber
				self.currentLine = linenumber

				self._triggerResendAt100 = True
				self._triggerResendWithTimeoutAt105 = True

				self._sendOk()
				continue
			elif data.startswith("N"):
				linenumber = int(re.search("N([0-9]+)", data).group(1))
				expected = self.lastN + 1
				if linenumber != expected:
					self._triggerResend(actual=linenumber)
					continue
				elif linenumber == 100 and self._triggerResendAt100:
					# simulate a resend at line 100
					self._triggerResendAt100 = False
					self._triggerResend(expected=100)
					continue
				elif linenumber == 105 and self._triggerResendWithTimeoutAt105 and not self._writingToSd:
					# simulate a resend with timeout at line 105
					self._triggerResendWithTimeoutAt105 = False
					self._triggerResend(expected=105)
					self._dont_answer = True
					self.lastN = linenumber
					continue
				elif linenumber == 110 and self._triggerResendWithMissingLinenoAt110 and not self._writingToSd:
					self._triggerResendWithMissingLinenoAt110 = False
					self._send(self._error("lineno_missing", self.lastN))
					continue
				elif linenumber == 115 and self._triggerResendWithChecksumMismatchAt115 and not self._writingToSd:
					self._triggerResendWithChecksumMismatchAt115 = False
					self._triggerResend(checksum=True)
					continue
				elif len(self._prepared_errors):
					prepared = self._prepared_errors.pop(0)
					if callable(prepared):
						prepared(linenumber, self.lastN, data)
						continue
					elif isinstance(prepared, basestring):
						self._send(prepared)
						continue
				else:
					self.lastN = linenumber
				data = data.split(None, 1)[1].strip()

			data += "\n"

			if data.startswith("!!DEBUG:") or data.strip() == "!!DEBUG":
				debug_command = ""
				if data.startswith("!!DEBUG:"):
					debug_command = data[len("!!DEBUG:"):].strip()
				self._debugTrigger(debug_command)
				continue

			# shortcut for writing to SD
			if self._writingToSd and self._writingToSdHandle is not None and not "M29" in data:
				self._writingToSdHandle.write(data)
				self._sendOk()
				continue

			if data.strip() == "version":
				from octoprint import __version__
				self._send("OctoPrint VirtualPrinter v" + __version__)
				continue

			# if we are sending oks before command output, send it now
			if len(data.strip()) > 0 and self._okBeforeCommandOutput:
				self._sendOk()

			# actual command handling
			command_match = VirtualPrinter.command_regex.match(data)
			if command_match is not None:
				command = command_match.group(0)
				letter = command_match.group(1)

				try:
					# if we have a method _gcode_G, _gcode_M or _gcode_T, execute that first
					letter_handler = "_gcode_{}".format(letter)
					if hasattr(self, letter_handler):
						code = command_match.group(2)
						handled = getattr(self, letter_handler)(code, data)
						if handled:
							continue

					# then look for a method _gcode_<command> and execute that if it exists
					command_handler = "_gcode_{}".format(command)
					if hasattr(self, command_handler):
						handled = getattr(self, command_handler)(data)
						if handled:
							continue

				finally:
					# make sure that the debug sleepAfter and sleepAfterNext stuff works even
					# if we continued above
					if len(self._sleepAfter) or len(self._sleepAfterNext):
						interval = None
						if command in self._sleepAfter:
							interval = self._sleepAfter[command]
						elif command in self._sleepAfterNext:
							interval = self._sleepAfterNext[command]
							del self._sleepAfterNext[command]

						if interval is not None:
							self._send("// sleeping for {interval} seconds".format(interval=interval))
							time.sleep(interval)

			# if we are sending oks after command output, send it now
			if len(data.strip()) > 0 and not self._okBeforeCommandOutput:
				self._sendOk()

		self._logger.info("Closing down read loop")
Пример #30
0
 def _cleanup_sessions(self):
     for session, user in self._session_users_by_session.items():
         if not isinstance(user, SessionUser):
             continue
         if user.created + (24 * 60 * 60) < monotonic_time():
             self.logout_user(user)
Пример #31
0
def gcode_command(
    path,
    speedx,
    speedy,
    speedz,
    offset,
    maxt,
    throttle,
    throttle_lines,
    g90_extruder,
    bedz,
    progress,
    layers,
):
    """Runs a GCODE file analysis."""

    import time

    import yaml

    from octoprint.util import monotonic_time
    from octoprint.util.gcodeInterpreter import gcode

    throttle_callback = None
    if throttle:

        def throttle_callback(filePos, readBytes):
            if filePos % throttle_lines == 0:
                # only apply throttle every $throttle_lines lines
                time.sleep(throttle)

    offsets = offset
    if offsets is None:
        offsets = []
    elif isinstance(offset, tuple):
        offsets = list(offsets)
    offsets = [(0, 0)] + offsets
    if len(offsets) < maxt:
        offsets += [(0, 0)] * (maxt - len(offsets))

    start_time = monotonic_time()

    progress_callback = None
    if progress:

        def progress_callback(percentage):
            click.echo("PROGRESS:{}".format(percentage))

    interpreter = gcode(progress_callback=progress_callback,
                        incl_layers=layers)

    interpreter.load(
        path,
        speedx=speedx,
        speedy=speedy,
        offsets=offsets,
        throttle=throttle_callback,
        max_extruders=maxt,
        g90_extruder=g90_extruder,
        bed_z=bedz,
    )

    click.echo("DONE:{}s".format(monotonic_time() - start_time))

    result = interpreter.get_result()
    if empty_result(result):
        click.echo(
            "EMPTY:There are no extrusions in the file, nothing to analyse")
        sys.exit(0)

    if not validate_result(result):
        click.echo(
            "ERROR:Invalid analysis result, please create a bug report in OctoPrint's "
            "issue tracker and be sure to also include the GCODE file with which this "
            "happened")
        sys.exit(-1)

    click.echo("RESULTS:")
    click.echo(
        yaml.safe_dump(
            interpreter.get_result(),
            default_flow_style=False,
            indent=2,
            allow_unicode=True,
        ))
Пример #32
0
	def _track_ping(self):
		if not self._settings.get_boolean([b"enabled"]):
			return

		uptime = int(monotonic_time() - self._startup_time)
		self._track("ping", octoprint_uptime=uptime)
Пример #33
0
 def touch(self):
     self._self_touched = monotonic_time()
Пример #34
0
	def gcode_received(self, comm, line, *args, **kwargs):				
		# Try to figure out buffer sizes for underrun detection by looking at the N0 M110 N0 response
		# Important: This runs before on_after_startup
		if self.planner_buffer_size == 0 and "ok N0 " in line:
			matches = ADVANCED_OK.search(line)
			if matches:
				# ok output always returns BLOCK_BUFFER_SIZE - 1 due to 
				#     FORCE_INLINE static uint8_t moves_free() { return BLOCK_BUFFER_SIZE - 1 - movesplanned(); }
				# for whatever reason
				planner_buffer_size = int(matches.group('planner_buffer_avail')) + 1
				# We add +1 here as ok will always return BUFSIZE-1 as we've just sent it a command
				command_buffer_size = int(matches.group('command_buffer_avail')) + 1
				self.set_buffer_sizes(planner_buffer_size, command_buffer_size)
				self.set_status('Buffer sizes detected')

		if self.did_resend and not comm._resendActive:
			self.did_resend = False
			self.set_status('Resend over, resuming...')

		if "ok " in line:
			matches = ADVANCED_OK.search(line)

			if matches is None or matches.group('line') is None:
				return line
				
			ok_line_number = int(matches.group('line'))
			current_line_number = comm._current_line
			command_buffer_avail = int(matches.group('command_buffer_avail'))
			planner_buffer_avail = int(matches.group('planner_buffer_avail'))
			queue_size = comm._send_queue._qsize()
			inflight_target = self.sd_inflight_target if comm.isStreaming() else self.inflight_target
			inflight = current_line_number - ok_line_number
			inflight += comm._clear_to_send._counter # If there's a clear_to_send pending, we need to count it as inflight cause it will be soon

			should_report = False
			should_send = False

			# If we're in a resend state, try to lower inflight commands by consuming ok's
			if comm._resendActive and self.enabled:
				if not self.did_resend:
					self.resends_detected += 1
					self.did_resend = True
					self.set_status('Resend detected, backing off')
				self.last_cts = monotonic_time() + POST_RESEND_WAIT # Hack to delay before resuming CTS after resend event to give printer some time to breathe
				if inflight > (inflight_target / 2):
					self._logger.warn("using a clear to decrease inflight, inflight: {}, line: {}".format(inflight, line))
					comm._ok_timeout = monotonic_time() + 0.05 # Reduce the timeout in case we eat too many OKs
					return None

			# detect underruns if printing
			if not comm.isStreaming():
				if command_buffer_avail == self.command_buffer_size - 1:
					self.command_underruns_detected += 1

				if planner_buffer_avail == self.planner_buffer_size - 1:
					self.planner_underruns_detected += 1

			if (monotonic_time() - self.last_report) > REPORT_INTERVAL:
				should_report = True

			if command_buffer_avail > 1: # aim to keep at least one spot free
				if inflight < inflight_target and (monotonic_time() - self.last_cts) > self.min_cts_interval:
					should_send = True

			if should_send and self.enabled:
				# Ensure _clear_to_send._max is at least 2, otherwise triggering _clear_to_send won't do anything
				if comm._clear_to_send._max < 2:
					self._logger.warn("setting 'ok buffer size' / comm._clear_to_send._max to 2 cause plugin doesn't work at 1")
					comm._clear_to_send._max = 2

				# If the command queue is empty, triggering clear_to_send won't do anything
				# so we try to make sure something's in there
				if queue_size == 0: 
					self._logger.debug("command queue empty, prod comm to send more with _continue_sending()")
					comm._continue_sending()
				self._logger.debug("detected available command buffer, triggering a send")
				# this enables the send loop to send if it's waiting
				comm._clear_to_send.set() # Is there a point calling this if _clear_to_send is at max?
				self.clear_to_sends_triggered += 1
				self.last_cts = monotonic_time()
				should_report = True

			if should_report:
				self.send_message("update", {
					"current_line_number": current_line_number,
					"acked_line_number": ok_line_number,
					"inflight": inflight,
					"planner_buffer_avail": planner_buffer_avail,
					"command_buffer_avail": command_buffer_avail,
					"resends_detected": self.resends_detected,
					"planner_underruns_detected": self.planner_underruns_detected,
					"command_underruns_detected": self.command_underruns_detected,
					"cts_triggered": self.clear_to_sends_triggered,
					"send_queue_size": queue_size,
				})
				self._logger.debug("current line: {} ok line: {} buffer avail: {} inflight: {} cts: {} cts_max: {} queue: {}".format(current_line_number, ok_line_number, command_buffer_avail, inflight, comm._clear_to_send._counter, comm._clear_to_send._max, queue_size))
				self.last_report = monotonic_time()
				if self.enabled:
					self.set_status('Active')
				else:
					self.set_status('Monitoring')

		return line
Пример #35
0
	def _cleanup_sessions(self):
		for session, user in self._session_users_by_session.items():
			if not isinstance(user, SessionUser):
				continue
			if user.created + (24 * 60 * 60) < monotonic_time():
				self.logout_user(user)
Пример #36
0
    def _track_ping(self):
        if not self._settings.get_boolean([b"enabled"]):
            return

        uptime = int(monotonic_time() - self._startup_time)
        self._track("ping", octoprint_uptime=uptime)
Пример #37
0
 def __init__(self):
     self._start_time = monotonic_time()
Пример #38
0
	def __init__(self, seriallog_handler=None, read_timeout=5.0, write_timeout=10.0):
		import logging
		self._logger = logging.getLogger("octoprint.plugins.virtual_printer.VirtualPrinter")

		self._seriallog = logging.getLogger("octoprint.plugin.virtual_printer.VirtualPrinter.serial")
		self._seriallog.setLevel(logging.CRITICAL)
		self._seriallog.propagate = False

		if seriallog_handler is not None:
			import logging.handlers
			self._seriallog.addHandler(seriallog_handler)
			self._seriallog.setLevel(logging.INFO)

		self._seriallog.info(u"-"*78)

		self._read_timeout = read_timeout
		self._write_timeout = write_timeout

		self._rx_buffer_size = settings().getInt(["devel", "virtualPrinter", "rxBuffer"])

		self.incoming = CharCountingQueue(self._rx_buffer_size, name="RxBuffer")
		self.outgoing = queue.Queue()
		self.buffered = queue.Queue(maxsize=settings().getInt(["devel", "virtualPrinter", "commandBuffer"]))

		if settings().getBoolean(["devel", "virtualPrinter", "simulateReset"]):
			for item in settings().get(["devel", "virtualPrinter", "resetLines"]):
				self._send(item + "\n")

		self._prepared_oks = []
		prepared = settings().get(["devel", "virtualPrinter", "preparedOks"])
		if prepared and isinstance(prepared, list):
			for prep in prepared:
				self._prepared_oks.append(prep)

		self._prepared_errors = []

		self._errors = settings().get(["devel", "virtualPrinter", "errors"], merged=True)

		self.currentExtruder = 0
		self.extruderCount = settings().getInt(["devel", "virtualPrinter", "numExtruders"])
		self.pinnedExtruders = settings().get(["devel", "virtualPrinter", "pinnedExtruders"])
		if self.pinnedExtruders is None:
			self.pinnedExtruders = dict()
		self.sharedNozzle = settings().getBoolean(["devel", "virtualPrinter", "sharedNozzle"])
		self.temperatureCount = (1 if self.sharedNozzle else self.extruderCount)

		self._ambient_temperature = settings().getFloat(["devel", "virtualPrinter", "ambientTemperature"])

		self.temp = [self._ambient_temperature] * self.temperatureCount
		self.targetTemp = [0.0] * self.temperatureCount
		self.bedTemp = self._ambient_temperature
		self.bedTargetTemp = 0.0
		self.chamberTemp = self._ambient_temperature
		self.chamberTargetTemp = 0.0
		self.lastTempAt = monotonic_time()

		self._relative = True
		self._lastX = 0.0
		self._lastY = 0.0
		self._lastZ = 0.0
		self._lastE = [0.0] * self.extruderCount
		self._lastF = 200

		self._unitModifier = 1
		self._feedrate_multiplier = 100
		self._flowrate_multiplier = 100

		self._virtualSd = settings().getBaseFolder("virtualSd")
		self._sdCardReady = True
		self._sdPrinter = None
		self._sdPrintingSemaphore = threading.Event()
		self._selectedSdFile = None
		self._selectedSdFileSize = None
		self._selectedSdFilePos = None

		self._writingToSd = False
		self._writingToSdHandle = None
		self._newSdFilePos = None

		self._heatingUp = False

		self._okBeforeCommandOutput = settings().getBoolean(["devel", "virtualPrinter", "okBeforeCommandOutput"])
		self._supportM112 = settings().getBoolean(["devel", "virtualPrinter", "supportM112"])
		self._supportF = settings().getBoolean(["devel", "virtualPrinter", "supportF"])

		self._sendWait = settings().getBoolean(["devel", "virtualPrinter", "sendWait"])
		self._sendBusy = settings().getBoolean(["devel", "virtualPrinter", "sendBusy"])
		self._waitInterval = settings().getFloat(["devel", "virtualPrinter", "waitInterval"])
		self._busyInterval = settings().getFloat(["devel", "virtualPrinter", "busyInterval"])

		self._echoOnM117 = settings().getBoolean(["devel", "virtualPrinter", "echoOnM117"])

		self._brokenM29 = settings().getBoolean(["devel", "virtualPrinter", "brokenM29"])
		self._brokenResend = settings().getBoolean(["devel", "virtualPrinter", "brokenResend"])

		self._m115FormatString = settings().get(["devel", "virtualPrinter", "m115FormatString"])
		self._firmwareName = settings().get(["devel", "virtualPrinter", "firmwareName"])

		self._okFormatString = settings().get(["devel", "virtualPrinter", "okFormatString"])

		self._capabilities = settings().get(["devel", "virtualPrinter", "capabilities"], merged=True)

		self._temperature_reporter = None
		self._sdstatus_reporter = None

		self.currentLine = 0
		self.lastN = 0

		self._incoming_lock = threading.RLock()

		self._debug_awol = False
		self._debug_sleep = None
		self._sleepAfterNext = dict()
		self._sleepAfter = dict()

		self._dont_answer = False

		self._debug_drop_connection = False

		self._action_hooks = plugin_manager().get_hooks("octoprint.plugin.virtual_printer.custom_action")

		self._killed = False

		self._triggerResendAt100 = True
		self._triggerResendWithTimeoutAt105 = True
		self._triggerResendWithMissingLinenoAt110 = True
		self._triggerResendWithChecksumMismatchAt115 = True

		readThread = threading.Thread(target=self._processIncoming, name="octoprint.plugins.virtual_printer.wait_thread")
		readThread.start()

		bufferThread = threading.Thread(target=self._processBuffer, name="octoprint.plugins.virtual_printer.buffer_thread")
		bufferThread.start()