From f19d0f0360ce102bd601fc571bb1c17878f136c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Tue, 5 May 2015 18:18:55 +0200 Subject: [PATCH] Base cut off point for temperature graph on timestamps instead of data points Cut off of the temperature graph is now not based on the number of data points any more but on the actual time of the data points. Anything older than ``n`` minutes will be cut off, with ``n`` defaulting to 30min. This value can be changed under "Temperatures" in the Settings Closes #343 --- CHANGELOG.md | 3 ++ src/octoprint/printer/standard.py | 12 ++++++- src/octoprint/server/api/settings.py | 4 ++- src/octoprint/settings.py | 3 +- .../static/js/app/viewmodels/settings.js | 7 ++-- .../static/js/app/viewmodels/temperature.js | 16 ++++++--- .../dialogs/settings/temperatures.jinja2 | 12 +++++++ src/octoprint/util/__init__.py | 33 +++++++++++++++++++ 8 files changed, 79 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc106bd5..dbdc4a48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -124,6 +124,9 @@ * Made baudrate detection a bit more solid, still can't perform wonders. * Only show configuration options for additional extruders if more than one is available, and don't include offset configuration for first nozzle which acts as reference for the other offsets ([#677](https://github.com/foosel/OctoPrint/issues/677)). +* Cut off of the temperature graph is now not based on the number of data points any more but on the actual time of the + data points. Anything older than ``n`` minutes will be cut off, with ``n`` defaulting to 30min. This value can be + changed under "Temperatures" in the Settings ([#343](https://github.com/foosel/OctoPrint/issues/343)). ### Bug Fixes diff --git a/src/octoprint/printer/standard.py b/src/octoprint/printer/standard.py index b09fa877..3991c6a5 100644 --- a/src/octoprint/printer/standard.py +++ b/src/octoprint/printer/standard.py @@ -23,6 +23,7 @@ from octoprint.printer import PrinterInterface, PrinterCallback, UnknownScript from octoprint.printer.estimation import TimeEstimationHelper from octoprint.settings import settings from octoprint.util import comm as comm +from octoprint.util import InvariantContainer class Printer(PrinterInterface, comm.MachineComPrintCallback): @@ -46,7 +47,7 @@ class Printer(PrinterInterface, comm.MachineComPrintCallback): self._bedTemp = None self._targetTemp = None self._targetBedTemp = None - self._temps = deque([], 300) + self._temps = TemperatureHistory(cutoff=settings().getInt(["temperature", "cutoff"])*60) self._tempBacklog = [] self._latestMessage = None @@ -937,3 +938,12 @@ class StateMonitor(object): } +class TemperatureHistory(InvariantContainer): + def __init__(self, cutoff=30 * 60): + + def temperature_invariant(data): + data.sort(key=lambda x: x["time"]) + now = int(time.time()) + return [item for item in data if item["time"] >= now - cutoff] + + InvariantContainer.__init__(self, guarantee_invariant=temperature_invariant) diff --git a/src/octoprint/server/api/settings.py b/src/octoprint/server/api/settings.py index 94169f71..f1143a62 100644 --- a/src/octoprint/server/api/settings.py +++ b/src/octoprint/server/api/settings.py @@ -89,7 +89,8 @@ def getSettings(): "watched": s.getBaseFolder("watched") }, "temperature": { - "profiles": s.get(["temperature", "profiles"]) + "profiles": s.get(["temperature", "profiles"]), + "cutoff": s.getInt(["temperature", "cutoff"]) }, "system": { "actions": s.get(["system", "actions"]), @@ -210,6 +211,7 @@ def setSettings(): if "temperature" in data.keys(): if "profiles" in data["temperature"].keys(): s.set(["temperature", "profiles"], data["temperature"]["profiles"]) + if "cutoff" in data["temperature"].keys(): s.setInt(["temperature", "cutoff"], data["temperature"]["cutoff"]) if "terminalFilters" in data.keys(): s.set(["terminalFilters"], data["terminalFilters"]) diff --git a/src/octoprint/settings.py b/src/octoprint/settings.py index 331b3e8f..2ad8969c 100644 --- a/src/octoprint/settings.py +++ b/src/octoprint/settings.py @@ -157,7 +157,8 @@ default_settings = { "profiles": [ {"name": "ABS", "extruder" : 210, "bed" : 100 }, {"name": "PLA", "extruder" : 180, "bed" : 60 } - ] + ], + "cutoff": 30 }, "printerProfiles": { "default": None, diff --git a/src/octoprint/static/js/app/viewmodels/settings.js b/src/octoprint/static/js/app/viewmodels/settings.js index 9fbdd38b..a4376913 100644 --- a/src/octoprint/static/js/app/viewmodels/settings.js +++ b/src/octoprint/static/js/app/viewmodels/settings.js @@ -109,8 +109,7 @@ $(function() { self.scripts_gcode_afterPrinterConnected = ko.observable(undefined); self.temperature_profiles = ko.observableArray(undefined); - - self.temperature_profiles = ko.observableArray(undefined); + self.temperature_cutoff = ko.observable(undefined); self.system_actions = ko.observableArray([]); @@ -260,6 +259,7 @@ $(function() { self.scripts_gcode_afterPrinterConnected(response.scripts.gcode.afterPrinterConnected); self.temperature_profiles(response.temperature.profiles); + self.temperature_cutoff(response.temperature.cutoff); self.system_actions(response.system.actions); @@ -334,7 +334,8 @@ $(function() { "watched": self.folder_watched() }, "temperature": { - "profiles": self.temperature_profiles() + "profiles": self.temperature_profiles(), + "cutoff": self.temperature_cutoff() }, "system": { "actions": self.system_actions() diff --git a/src/octoprint/static/js/app/viewmodels/temperature.js b/src/octoprint/static/js/app/viewmodels/temperature.js index 85af5bdb..4657630a 100644 --- a/src/octoprint/static/js/app/viewmodels/temperature.js +++ b/src/octoprint/static/js/app/viewmodels/temperature.js @@ -32,6 +32,7 @@ $(function() { self.isLoading = ko.observable(undefined); self.temperature_profiles = self.settingsViewModel.temperature_profiles; + self.temperature_cutoff = self.settingsViewModel.temperature_cutoff; self.heaterOptions = ko.observable({}); @@ -161,11 +162,6 @@ $(function() { if (!CONFIG_TEMPERATURE_GRAPH) return; self.temperatures = self._processTemperatureData(data, self.temperatures); - _.each(_.keys(self.heaterOptions()), function(d) { - self.temperatures[d].actual = self.temperatures[d].actual.slice(-300); - self.temperatures[d].target = self.temperatures[d].target.slice(-300); - }); - self.updatePlot(); }; @@ -215,6 +211,16 @@ $(function() { }) }); + var now = Date.now(); + var filterOld = function(item) { + return item[0] >= now - self.temperature_cutoff() * 60 * 1000; + }; + + _.each(_.keys(self.heaterOptions()), function(d) { + result[d].actual = _.filter(result[d].actual, filterOld); + result[d].target = _.filter(result[d].target, filterOld); + }); + return result; }; diff --git a/src/octoprint/templates/dialogs/settings/temperatures.jinja2 b/src/octoprint/templates/dialogs/settings/temperatures.jinja2 index 4800e057..e0f5086b 100644 --- a/src/octoprint/templates/dialogs/settings/temperatures.jinja2 +++ b/src/octoprint/templates/dialogs/settings/temperatures.jinja2 @@ -1,4 +1,16 @@
+

{{ _('Temperature Graph') }}

+
+ +
+
+ + min +
+ {{ _('Needs a restart of OctoPrint to become active.') }} +
+
+

{{ _('Temperature Presets') }}

{{ _('Extruder') }}

{{ _('Bed') }}

diff --git a/src/octoprint/util/__init__.py b/src/octoprint/util/__init__.py index b2d2a6e7..a682578a 100644 --- a/src/octoprint/util/__init__.py +++ b/src/octoprint/util/__init__.py @@ -649,3 +649,36 @@ class CountedEvent(object): self._counter = self._max self._event.set() self._logger.debug("Set event") + + +class InvariantContainer(object): + def __init__(self, initial_data=None, guarantee_invariant=None): + from collections import Iterable + from threading import RLock + + if guarantee_invariant is None: + guarantee_invariant = lambda data: data + + self._data = [] + self._mutex = RLock() + self._invariant = guarantee_invariant + + if initial_data is not None and isinstance(initial_data, Iterable): + for item in initial_data: + self.append(item) + + def append(self, item): + with self._mutex: + self._data.append(item) + self._data = self._invariant(self._data) + + def remove(self, item): + with self._mutex: + self._data.remove(item) + self._data = self._invariant(self._data) + + def __len__(self): + return len(self._data) + + def __iter__(self): + return self._data.__iter__() \ No newline at end of file