Option to automatically send temperature fine adjustments
As suggested by a loyal Patron ;)
This commit is contained in:
parent
8ad165c625
commit
b2c1bb4b53
7 changed files with 129 additions and 17 deletions
|
|
@ -264,13 +264,17 @@ class PluginSettings(object):
|
|||
:returns: The retrieved settings value.
|
||||
:rtype: object
|
||||
|
||||
.. method:: get_int(path)
|
||||
.. method:: get_int(path, min=None, max=None)
|
||||
|
||||
Like :func:`get` but tries to convert the retrieved value to ``int``.
|
||||
Like :func:`get` but tries to convert the retrieved value to ``int``. If ``min`` is provided and the retrieved
|
||||
value is less than it, it will be returned instead of the value. Likewise for ``max`` - it will be returned if
|
||||
the value is greater than it.
|
||||
|
||||
.. method:: get_float(path)
|
||||
.. method:: get_float(path, min=None, max=None)
|
||||
|
||||
Like :func:`get` but tries to convert the retrieved value to ``float``.
|
||||
Like :func:`get` but tries to convert the retrieved value to ``float``. If ``min`` is provided and the retrieved
|
||||
value is less than it, it will be returned instead of the value. Likewise for ``max`` - it will be returned if
|
||||
the value is greater than it.
|
||||
|
||||
.. method:: get_boolean(path)
|
||||
|
||||
|
|
@ -286,13 +290,19 @@ class PluginSettings(object):
|
|||
:param boolean force: If set to True, the modified configuration will even be written back to disk if
|
||||
the value didn't change.
|
||||
|
||||
.. method:: set_int(path, value, force=False)
|
||||
.. method:: set_int(path, value, force=False, min=None, max=None)
|
||||
|
||||
Like :func:`set` but ensures the value is an ``int`` through attempted conversion before setting it.
|
||||
If ``min`` and/or ``max`` are provided, it will also be ensured that the value is greater than or equal
|
||||
to ``min`` and less than or equal to ``max``. If that is not the case, the limit value (``min`` if less than
|
||||
that, ``max`` if greater than that) will be set instead.
|
||||
|
||||
.. method:: set_float(path, value, force=False)
|
||||
.. method:: set_float(path, value, force=False, min=None, max=None)
|
||||
|
||||
Like :func:`set` but ensures the value is an ``float`` through attempted conversion before setting it.
|
||||
If ``min`` and/or ``max`` are provided, it will also be ensured that the value is greater than or equal
|
||||
to ``min`` and less than or equal to ``max``. If that is not the case, the limit value (``min`` if less than
|
||||
that, ``max`` if greater than that) will be set instead.
|
||||
|
||||
.. method:: set_boolean(path, value, force=False)
|
||||
|
||||
|
|
|
|||
|
|
@ -168,7 +168,9 @@ def getSettings():
|
|||
},
|
||||
"temperature": {
|
||||
"profiles": s.get(["temperature", "profiles"]),
|
||||
"cutoff": s.getInt(["temperature", "cutoff"])
|
||||
"cutoff": s.getInt(["temperature", "cutoff"]),
|
||||
"sendAutomatically": s.getBoolean(["temperature", "sendAutomatically"]),
|
||||
"sendAutomaticallyAfter": s.getInt(["temperature", "sendAutomaticallyAfter"], min=0, max=30),
|
||||
},
|
||||
"system": {
|
||||
"actions": s.get(["system", "actions"]),
|
||||
|
|
@ -388,6 +390,8 @@ def _saveSettings(data):
|
|||
if "temperature" in data.keys():
|
||||
if "profiles" in data["temperature"]: s.set(["temperature", "profiles"], data["temperature"]["profiles"])
|
||||
if "cutoff" in data["temperature"]: s.setInt(["temperature", "cutoff"], data["temperature"]["cutoff"])
|
||||
if "sendAutomatically" in data["temperature"]: s.setBoolean(["temperature", "sendAutomatically"], data["temperature"]["sendAutomatically"])
|
||||
if "sendAutomaticallyAfter" in data["temperature"]: s.setInt(["temperature", "sendAutomaticallyAfter"], data["temperature"]["sendAutomaticallyAfter"], min=0, max=30)
|
||||
|
||||
if "terminalFilters" in data.keys():
|
||||
s.set(["terminalFilters"], data["terminalFilters"])
|
||||
|
|
|
|||
|
|
@ -231,7 +231,9 @@ default_settings = {
|
|||
{"name": "ABS", "extruder" : 210, "bed" : 100 },
|
||||
{"name": "PLA", "extruder" : 180, "bed" : 60 }
|
||||
],
|
||||
"cutoff": 30
|
||||
"cutoff": 30,
|
||||
"sendAutomatically": False,
|
||||
"sendAutomaticallyAfter": 1,
|
||||
},
|
||||
"printerProfiles": {
|
||||
"default": None
|
||||
|
|
@ -1275,23 +1277,43 @@ class Settings(object):
|
|||
return None
|
||||
|
||||
def getInt(self, path, **kwargs):
|
||||
minimum = kwargs.pop("min", None)
|
||||
maximum = kwargs.pop("max", None)
|
||||
|
||||
value = self.get(path, **kwargs)
|
||||
if value is None:
|
||||
return None
|
||||
|
||||
try:
|
||||
return int(value)
|
||||
intValue = int(value)
|
||||
|
||||
if minimum is not None and intValue < minimum:
|
||||
return minimum
|
||||
elif maximum is not None and intValue > maximum:
|
||||
return maximum
|
||||
else:
|
||||
return intValue
|
||||
except ValueError:
|
||||
self._logger.warn("Could not convert %r to a valid integer when getting option %r" % (value, path))
|
||||
return None
|
||||
|
||||
def getFloat(self, path, **kwargs):
|
||||
minimum = kwargs.pop("min", None)
|
||||
maximum = kwargs.pop("max", None)
|
||||
|
||||
value = self.get(path, **kwargs)
|
||||
if value is None:
|
||||
return None
|
||||
|
||||
try:
|
||||
return float(value)
|
||||
floatValue = float(value)
|
||||
|
||||
if minimum is not None and floatValue < minimum:
|
||||
return minimum
|
||||
elif maximum is not None and floatValue > maximum:
|
||||
return maximum
|
||||
else:
|
||||
return floatValue
|
||||
except ValueError:
|
||||
self._logger.warn("Could not convert %r to a valid integer when getting option %r" % (value, path))
|
||||
return None
|
||||
|
|
@ -1447,8 +1469,16 @@ class Settings(object):
|
|||
self.set(path, None, **kwargs)
|
||||
return
|
||||
|
||||
minimum = kwargs.pop("min", None)
|
||||
maximum = kwargs.pop("max", None)
|
||||
|
||||
try:
|
||||
intValue = int(value)
|
||||
|
||||
if minimum is not None and intValue < minimum:
|
||||
intValue = minimum
|
||||
if maximum is not None and intValue > maximum:
|
||||
intValue = maximum
|
||||
except ValueError:
|
||||
self._logger.warn("Could not convert %r to a valid integer when setting option %r" % (value, path))
|
||||
return
|
||||
|
|
@ -1460,8 +1490,16 @@ class Settings(object):
|
|||
self.set(path, None, **kwargs)
|
||||
return
|
||||
|
||||
minimum = kwargs.pop("min", None)
|
||||
maximum = kwargs.pop("max", None)
|
||||
|
||||
try:
|
||||
floatValue = float(value)
|
||||
|
||||
if minimum is not None and floatValue < minimum:
|
||||
floatValue = minimum
|
||||
if maximum is not None and floatValue > maximum:
|
||||
floatValue = maximum
|
||||
except ValueError:
|
||||
self._logger.warn("Could not convert %r to a valid integer when setting option %r" % (value, path))
|
||||
return
|
||||
|
|
|
|||
|
|
@ -195,6 +195,8 @@ $(function() {
|
|||
|
||||
self.temperature_profiles = ko.observableArray(undefined);
|
||||
self.temperature_cutoff = ko.observable(undefined);
|
||||
self.temperature_sendAutomatically = ko.observable(undefined);
|
||||
self.temperature_sendAutomaticallyAfter = ko.observable(undefined);
|
||||
|
||||
self.system_actions = ko.observableArray([]);
|
||||
|
||||
|
|
|
|||
|
|
@ -454,11 +454,14 @@ $(function() {
|
|||
|
||||
self.incrementTarget = function(item) {
|
||||
var value = item.newTarget();
|
||||
if (value === undefined || (typeof(value) == "string" && value.trim() == "")) value = item.target();
|
||||
if (value === undefined || (typeof(value) == "string" && value.trim() == "")) {
|
||||
value = item.target();
|
||||
}
|
||||
try {
|
||||
value = parseInt(value);
|
||||
if (value > 999) return;
|
||||
item.newTarget(value + 1);
|
||||
self.autosendTarget(item);
|
||||
} catch (ex) {
|
||||
// do nothing
|
||||
}
|
||||
|
|
@ -466,33 +469,69 @@ $(function() {
|
|||
|
||||
self.decrementTarget = function(item) {
|
||||
var value = item.newTarget();
|
||||
if (value === undefined || (typeof(value) == "string" && value.trim() == "")) value = item.target();
|
||||
if (value === undefined || (typeof(value) == "string" && value.trim() == "")) {
|
||||
value = item.target();
|
||||
}
|
||||
try {
|
||||
value = parseInt(value);
|
||||
if (value <= 0) return;
|
||||
item.newTarget(value - 1);
|
||||
self.autosendTarget(item);
|
||||
} catch (ex) {
|
||||
// do nothing
|
||||
}
|
||||
};
|
||||
|
||||
var _sendTimeout = {};
|
||||
|
||||
self.autosendTarget = function(item) {
|
||||
if (!self.settingsViewModel.temperature_sendAutomatically()) return;
|
||||
var delay = self.settingsViewModel.temperature_sendAutomaticallyAfter() * 1000;
|
||||
|
||||
var name = item.name();
|
||||
if (_sendTimeout[name]) {
|
||||
window.clearTimeout(_sendTimeout[name]);
|
||||
}
|
||||
_sendTimeout[name] = window.setTimeout(function() {
|
||||
self.setTarget(item);
|
||||
delete _sendTimeout[name];
|
||||
}, delay);
|
||||
};
|
||||
|
||||
self.clearAutosendTarget = function(item) {
|
||||
var name = item.name();
|
||||
if (_sendTimeout[name]) {
|
||||
window.clearTimeout(_sendTimeout[name]);
|
||||
delete _sendTimeout[name];
|
||||
}
|
||||
};
|
||||
|
||||
self.setTarget = function(item, form) {
|
||||
var value = item.newTarget();
|
||||
$(form).find("input").blur();
|
||||
if (form !== undefined) {
|
||||
$(form).find("input").blur();
|
||||
}
|
||||
if (value === undefined || (typeof(value) == "string" && value.trim() == "")) return OctoPrintClient.createRejectedDeferred();
|
||||
|
||||
self.clearAutosendTarget(item);
|
||||
return self.setTargetToValue(item, value);
|
||||
};
|
||||
|
||||
self.setTargetFromProfile = function(item, profile) {
|
||||
if (!profile) return OctoPrintClient.createRejectedDeferred();
|
||||
|
||||
self.clearAutosendTarget(item);
|
||||
return self.setTargetToValue(item, (item.key() == "bed" ? profile.bed : profile.extruder));
|
||||
};
|
||||
|
||||
self.setTargetToZero = function(item) {
|
||||
self.clearAutosendTarget(item);
|
||||
return self.setTargetToValue(item, 0);
|
||||
};
|
||||
|
||||
self.setTargetToValue = function(item, value) {
|
||||
self.clearAutosendTarget(item);
|
||||
|
||||
try {
|
||||
value = parseInt(value);
|
||||
} catch (ex) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<form class="form-horizontal">
|
||||
<h3>{{ _('Temperature Graph') }}</h3>
|
||||
<h3>{{ _('Graph') }}</h3>
|
||||
<div class="control-group">
|
||||
<label class="control-label">{{ _('Graph cutoff') }}</label>
|
||||
<div class="controls">
|
||||
|
|
@ -10,7 +10,26 @@
|
|||
<span class="help-block">{{ _('Needs a restart of OctoPrint to become active.') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<h3>{{ _('Temperature Presets') }}</h3>
|
||||
<h3>{{ _('Fine adjustments') }}</h3>
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" data-bind="checked: temperature_sendAutomatically"> {{ _('Send temperature fine adjustments automatically') }}
|
||||
</label>
|
||||
<span class="help-block">{{ _('Enable this to have temperature fine adjustments you do via the + or - button be sent to the printer automatically.') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group" data-bind="visible: temperature_sendAutomatically">
|
||||
<label class="control-label">{{ _('Sending delay') }}</label>
|
||||
<div class="controls">
|
||||
<div class="input-append">
|
||||
<input type="number" class="input-mini" min="0" max="30" data-bind="value: temperature_sendAutomaticallyAfter">
|
||||
<span class="add-on">sec</span>
|
||||
</div>
|
||||
<span class="help-block">{{ _('OctoPrint will use this delay to limit the number of sent temperature commands should you perform multiple fine adjustments in a short time.') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<h3>{{ _('Presets') }}</h3>
|
||||
<div class="row-fluid">
|
||||
<div class="offset4 span3"><h4>{{ _('Extruder') }}</h4></div>
|
||||
<div class="span3"><h4>{{ _('Bed') }}</h4></div>
|
||||
|
|
|
|||
|
|
@ -24,10 +24,10 @@
|
|||
<td class="temperature_target">
|
||||
<form class="form-inline" style="margin:0" data-bind="submit: function(element) { $root.setTarget($data, element) }">
|
||||
<div class="input-prepend input-append">
|
||||
<button type="button" class="btn btn-input-dec" data-bind="click: $root.decrementTarget, enable: $root.isOperational() && $root.loginState.isUser()" title="{{ _('-1') }}"><i class="fa fa-minus"></i></button>
|
||||
<button type="button" class="btn btn-input-dec" data-bind="click: $root.decrementTarget, enable: $root.isOperational() && $root.loginState.isUser()" title="{{ _('Fine adjust: -1°C') }}"><i class="fa fa-minus"></i></button>
|
||||
<input type="number" min="0" max="999" class="input-mini input-nospin" style="width: 30px" data-bind="attr: {placeholder: cleanTemperature(target())}, value: newTarget, valueUpdate: 'input', enable: $root.isOperational() && $root.loginState.isUser(), event: { focus: function(d, e) {$root.handleFocus(e, 'target', $data) } }">
|
||||
<span class="add-on">°C</span>
|
||||
<button type="button" class="btn btn-input-inc" data-bind="click: $root.incrementTarget, enable: $root.isOperational() && $root.loginState.isUser()" title="{{ _('+1') }}"><i class="fa fa-plus"></i></button>
|
||||
<button type="button" class="btn btn-input-inc" data-bind="click: $root.incrementTarget, enable: $root.isOperational() && $root.loginState.isUser()" title="{{ _('Fine adjust: +1°C') }}"><i class="fa fa-plus"></i></button>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button type="submit" data-bind="enable: $root.isOperational() && $root.loginState.isUser() && $data.newTargetValid()" class="btn btn-primary" title="{{ _('Set') }}"><i class="fa fa-check"></i></button>
|
||||
|
|
|
|||
Loading…
Reference in a new issue