Compare commits

..

No commits in common. "master" and "0.1.2" have entirely different histories.

9 changed files with 82 additions and 400 deletions

View File

@ -8,19 +8,7 @@ Add a slider to control the speed of a parts cooling fan.
Slide the slider, click the button. There really isn't much else to do :)
## Settings
* The default value of the slider is user configurable, this is the value that the slider will be set to upon loading OctoPrint's UI, and any time you refresh the page.
* The remember last speed checkbox will tell the plugin to save the fan speed as it gets sent to the printer, and set the slider to that value on load / refresh (overrides the default value setting).
* The minimum fan speed setting will limit how slow the fan runs, this is useful since some fans don't work below a certain speed.
* The maximum fan speed setting will limit how fast the fan runs, this is useful if your fan is too strong, or you wish to limit the speed post-slice without having to re-slice your file.
* "Disable M106 / M107" will disable the controls and reject all M106/M107 commands before they're sent to the printer. This setting has a corresponding padlock button beside the off button, both the padlock button and this setting in the settings page do exactly the same thing. This setting is here only as a convenience.
* Notification autohide delay controls how long any notifications will remain on the screen for. If the user manually sets a speed outside of the set range, a notification will be displayed informing the user the fan speed has been modified. Print jobs shouldn't trigger these notifications, and so popup spam shouldn't occur, however if a user wishes not to receive notifications when setting fan speeds outside of the set range, this value can be set to 0 (zero) to disable notifications. (this setting won't / shouldn't affect OctoPrint's global notifications, it only applies to info popups generated by this plugin).
The default value of the slider is user configurable, this is the value that the slider will be set to upon loading OctoPrint's UI, and any time you refresh the page. The default value setting does __NOT__ limit the output of the fan, if you set the default value to 10% and set the fan to 100% it will still come on at 100%. To limit the min/max speed of your fan during a print, please see your slicer's documentation and settings.
*Note: Slider does __not__ follow the speed of the fan. If the fan speed is set via gcode or an LCD panel on the printer, the slider will not respond to the change. It is a __setting__, not an indicator, and functions the same way the feedrate and flowrate sliders do.*

View File

@ -1,38 +0,0 @@
---
layout: plugin
id: fanslider
title: Fan Speed Control
description: Control your parts cooling fan
author: ntoff
license: AGPLv3
date: 2017-12-02
homepage: https://github.com/ntoff/OctoPrint-FanSpeedSlider
source: https://github.com/ntoff/OctoPrint-FanSpeedSlider
archive: https://github.com/ntoff/OctoPrint-FanSpeedSlider/archive/master.zip
tags:
- UI
- Controls
screenshots:
- url: /assets/img/plugins/fanslider/slider.JPG
alt: slider
caption: slider
- url: /assets/img/plugins/fanslider/settings.png
alt: settings
caption: settings
featuredimage: /assets/img/plugins/fanslider/slider.JPG
compatibility:
octoprint:
- 1.3.5
---
Adds a slider to the controls page for setting the speed of your parts cooling fan, and a settings page that allows limiting the fan's output power.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -1,8 +1,6 @@
# coding=utf-8
from __future__ import absolute_import
from decimal import *
import re
import octoprint.plugin
class FanSliderPlugin(octoprint.plugin.StartupPlugin,
@ -10,70 +8,8 @@ class FanSliderPlugin(octoprint.plugin.StartupPlugin,
octoprint.plugin.SettingsPlugin,
octoprint.plugin.AssetPlugin):
def __init__(self):
self.minPWM=0,
self.maxPWM=255,
self.lockfan=False
def on_after_startup(self):
self.get_settings_updates()
def get_settings_defaults(self):
return dict(
defaultFanSpeed=100,
minSpeed=0,
maxSpeed=100,
notifyDelay=4000,
lockfan=False,
lastSentSpeed=0,
defaultLastSpeed=False
)
def on_settings_save(self, data):
s = self._settings
if "defaultFanSpeed" in data.keys():
s.setInt(["defaultFanSpeed"], data["defaultFanSpeed"])
if "minSpeed" in data.keys():
s.setInt(["minSpeed"], data["minSpeed"])
if "maxSpeed" in data.keys():
s.setInt(["maxSpeed"], data["maxSpeed"])
if "notifyDelay" in data.keys():
s.setInt(["notifyDelay"], data["notifyDelay"])
if "lockfan" in data.keys():
s.set(["lockfan"], data["lockfan"])
if "lastSentSpeed" in data.keys():
s.setInt(["lastSentSpeed"], data["lastSentSpeed"])
if "defaultLastSpeed" in data.keys():
s.set(["defaultLastSpeed"], data["defaultLastSpeed"])
self.get_settings_updates()
#clean up settings if everything's default
self.on_settings_cleanup()
s.save()
#function stolen...err borrowed :D from types.py @ 1663
def on_settings_cleanup(self):
import octoprint.util
from octoprint.settings import NoSuchSettingsPath
try:
config = self._settings.get_all_data(merged=False, incl_defaults=False, error_on_path=True)
except NoSuchSettingsPath:
return
if config is None:
self._settings.clean_all_data()
return
if self.config_version_key in config and config[self.config_version_key] is None:
del config[self.config_version_key]
defaults = self.get_settings_defaults()
diff = octoprint.util.dict_minimal_mergediff(defaults, config)
if not diff:
self._settings.clean_all_data()
else:
self._settings.set([], diff)
return dict(fanSpeed=100)
def get_assets(self):
return dict(
@ -86,37 +22,10 @@ class FanSliderPlugin(octoprint.plugin.StartupPlugin,
dict(type="settings", custom_bindings=False)
]
def get_settings_updates(self):
self.defaultFanSpeed = self._settings.getInt(["defaultFanSpeed"])
self.minSpeed = self._settings.getInt(["minSpeed"])
self.maxSpeed = self._settings.getInt(["maxSpeed"])
self.lockfan = self._settings.get(["lockfan"])
getcontext().prec=5 #sets precision for "Decimal" not sure if this'll cause conflicts, ideas?
self.minPWM = round( Decimal(self.minSpeed) * Decimal(2.55), 2 )
self.maxPWM = round( Decimal(self.maxSpeed) * Decimal(2.55), 2 )
def rewrite_m106(self, comm_instance, phase, cmd, cmd_type, gcode, *args, **kwargs):
if gcode and gcode.startswith('M106') and not self.lockfan:
fanPwm = re.search("S(\d+\.?\d*)", cmd)
if fanPwm and fanPwm.group(1):
fanPwm = fanPwm.group(1)
if Decimal(fanPwm) < self.minPWM and Decimal(fanPwm) != 0:
self._logger.info("fan pwm value " + str(fanPwm) + " is below threshold, increasing to " + str(self.minPWM) + " (" + str(self.minSpeed) + "%)")
cmd = "M106 S" + str(self.minPWM)
return cmd,
elif Decimal(fanPwm) > self.maxPWM:
self._logger.info("fan pwm value " + str(fanPwm) + " is above threshold, decreasing to " + str(self.maxPWM) + " (" + str(self.maxSpeed) + "%)")
cmd = "M106 S" + str(self.maxPWM)
return cmd,
elif gcode and gcode.startswith(('M106', 'M107')) and self.lockfan:
self._logger.info("A cooling fan control command was seen, but fanspeedslider is locked. Control command " + str(cmd) + " removed from queue.")
return None,
def get_update_information(self):
return dict(
fanspeedslider=dict(
displayName="Fan Speed Control",
displayName="Fan Speed Slider",
displayVersion=self._plugin_version,
# version check: github repository
@ -129,16 +38,8 @@ class FanSliderPlugin(octoprint.plugin.StartupPlugin,
pip="https://github.com/ntoff/OctoPrint-FanSpeedSlider/archive/{target_version}.zip"
)
)
__plugin_name__ = "Fan Speed Control"
__plugin_pythoncompat__ = ">=2.7,<4"
def __plugin_load__():
global __plugin_implementation__
__plugin_implementation__ = __plugin_implementation__ = FanSliderPlugin()
global __plugin_hooks__
__plugin_hooks__ = {
"octoprint.comm.protocol.gcode.queuing": __plugin_implementation__.rewrite_m106,
__plugin_name__ = "Fan Speed Slider"
__plugin_implementation__ = FanSliderPlugin()
__plugin_hooks__ = {
"octoprint.plugin.softwareupdate.check_config": __plugin_implementation__.get_update_information
}

View File

@ -1,3 +1,20 @@
div#settings_plugin_fanspeedslider div {
width: 90%;
#touch body #control #control-fan-slider {
padding: 30px 0 15px 15px;
width: 50%;
}
#touch body #control #control-fan-slider button, #touch body #control #control-fan-slider input {
padding: 10px 20px;
margin: 0 0 20px;
width: 100%;
min-height: 40px;
height: auto;
-ms-box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
div#settings_plugin_fanspeedslider div {
width: 80%;
}

View File

@ -2,201 +2,64 @@
* Author: ntoff
* License: AGPLv3
*/
$(function () {
$(function() {
function FanSliderPluginViewModel(parameters) {
//'use strict';
var self = this;
self.settings = parameters[0];
self.control = parameters[1];
self.loginState = parameters[2];
self.printerstate = parameters[0];
self.loginstate = parameters[1];
self.control = parameters[2];
self.settings = parameters[3];
self.settings.defaultFanSpeed = new ko.observable(100); //this,
self.control.fanSpeed = new ko.observable(100); //this,
self.settings.minFanSpeed = new ko.observable(0); //this,
self.settings.maxFanSpeed = new ko.observable(100); //and this are percents 0 - 100%
self.settings.notifyDelay = new ko.observable(4000); //time in milliseconds
self.settings.lockfan = new ko.observable(false); //ignore fan inputs from gcode and lock the fan buttons
self.settings.defaultLastSpeed = new ko.observable(false); //options page option to set the slider to the last sent fan speed value on load/refresh
self.settings.lastSentSpeed = new ko.observable(null); //the last speed value that was sent to the printer
self.control.lockTitle = new ko.observable(gettext("Unlocked")); //will set the hover title info for the fan lock button
//Not sure why I put these here, I swear I had a plan when I did it, something about dynamic text? I dunno, should move it back to the settings page
self.settings.commonTitle = ko.observable(gettext("\n\nThis allows limiting the cooling fan without having to re-slice your model.\n\nLimited to prints controlled by OctoPrint."));
self.settings.defaultTitle = ko.observable(gettext("This is the value the slider will default to when the UI is loaded / refreshed."));
self.settings.minTitle = ko.observable(gettext("Set this to the lowest value at which your fan will spin.") + self.settings.commonTitle());
self.settings.maxTitle = ko.observable(gettext("Set this <100% if your cooling fan is too strong on full.") + self.settings.commonTitle());
self.settings.noticeTitle = ko.observable(gettext("Notifications only apply when setting the speed via the slider + button in the UI. Set to 0 (zero) to disable notifications."));
self.settings.lastspeedTitle = ko.observable(gettext("Instead of defaulting to the speed set by \"Default Value\", the slider will be set to the last sent speed on load / refresh. \n\n Note: It takes into account the min/max value setting and overrides the \"Default Value\" setting."));
self.showNotify = function (self, options) {
options.title = "Fan Speed Control";
options.delay = options.delay || self.settings.notifyDelay();
options.type = options.type || "info";
if (options.delay != "0") {
new PNotify(options);
}
};
self.control.fanSpeedToPwm = ko.pureComputed(function () {
self.speed = self.control.fanSpeed() * 255 / 100 //don't forget to limit this to 2 decimal places at some point.
return self.speed;
//default to 100% fan speed
fanSpeed = ko.observable(undefined);
//convert percentage into PWM
fanPWM = ko.pureComputed(function () {
return Math.round(fanSpeed() * 255 / 100);
});
self.control.checkSliderValue = ko.pureComputed(function () {
if (self.control.fanSpeed() < self.settings.minFanSpeed() && self.control.fanSpeed() != "0") {
console.log("Fan Speed Control Plugin: " + self.control.fanSpeed() + "% is less than the minimum speed (" + self.settings.minFanSpeed() + "%), increasing.");
self.control.fanSpeed(self.settings.minFanSpeed());
var options = {
hide: true,
text: gettext('Fan speed increased to meet minimum speed requirement.'),
addclass: 'fan_speed_notice_low',
}
if ($(".fan_speed_notice_low").length <1) {
self.showNotify(self, options);
}
}
else if (self.control.fanSpeed() > self.settings.maxFanSpeed()) {
console.log("Fan Speed Control Plugin: " + self.control.fanSpeed() + "% is more than the maximum speed (" + self.settings.maxFanSpeed() + "%), decreasing.");
self.control.fanSpeed(self.settings.maxFanSpeed());
var options = {
hide: true,
text: gettext('Fan speed decreased to meet maximum speed requirement.'),
addclass: 'fan_speed_notice_high',
}
if ($(".fan_speed_notice_high").length <1) {
self.showNotify(self, options);
}
}
});
//send gcode to set fan speed
self.control.sendFanSpeed = function () {
self.control.checkSliderValue();
self.control.sendCustomCommand({ command: "M106 S" + self.control.fanSpeedToPwm() });
if (self.settings.defaultLastSpeed()) {
self.settings.settings.plugins.fanspeedslider.lastSentSpeed(self.control.fanSpeed());
self.settings.saveData();
self.updateSettings();
}
sendFanSpeed = function () {
self.control.sendCustomCommand({ command: "M106 S" + fanPWM() });
};
self.control.lockFanInput = function () {
self.settings.settings.plugins.fanspeedslider.lockfan(!self.settings.settings.plugins.fanspeedslider.lockfan());
self.settings.saveData();
self.updateSettings();
var options = {
type: "info",
hide: true,
delay: 1000*60,
text: gettext('CAUTION!! Fan speed commands are now being ignored! \n This includes commands sent via gcode and the terminal!'),
addclass: 'fan_speed_notice_fanlocked',
}
if (self.settings.lockfan() && $(".fan_speed_notice_fanlocked").length <1) {
self.showNotify(self, options);
}
}
//disables the on/off buttons if the lock is enabled
self.control.islocked = ko.pureComputed(function () {
return self.settings.settings.plugins.fanspeedslider.lockfan();
});
//ph34r
try {
//for some reason touchui uses "jog general" for the fan controls? Oh well, makes my job easier
$("#control-jog-general").find("button").eq(0).attr("id", "motors-off");
$("#control-jog-general").find("button").eq(1).attr("id", "fan-on");
$("#control-jog-general").find("button").eq(2).attr("id", "fan-off");
//If not TouchUI then remove standard buttons + add slider + new buttons
if ($("#touch body").length == 0) {
//extra classes
$("#control > div.jog-panel").eq(0).addClass("controls");
$("#control > div.jog-panel").eq(1).addClass("tools");
$("#control > div.jog-panel").eq(2).addClass("general");
//If !TouchUI then remove standard buttons + add slider + new buttons
if ($("#touch body").length ==0 ) {
//add ID to buttons
$("#control > div.general").find("button").eq(0).attr("id", "motors-off");
$("#control > div.general").find("button").eq(1).attr("id", "fan-on");
$("#control > div.general").find("button").eq(2).attr("id", "fan-off");
//remove original fan on/off buttons
$("#fan-on").remove();
$("#fan-off").remove();
//add new fan controls
$("#control-jog-general").find("button").eq(0).before("\
<input type=\"number\" style=\"width: 95px\" data-bind=\"slider: {min: 00, max: 100, step: 1, value: fanSpeed, tooltip: 'hide'}\">\
<button class=\"btn btn-block control-box\" id=\"fan-on\" data-bind=\"enable: isOperational() && loginState.isUser() && !islocked(), click: function() { $root.sendFanSpeed() }\">" + gettext("Fan speed") + ":<span data-bind=\"text: fanSpeed() + '%'\"></span></button>\
<div class=\"btn-group\">\
<button class=\"btn \" id=\"fan-off\" data-bind=\"enable: isOperational() && loginState.isUser() && !islocked(), click: function() { $root.sendCustomCommand({ type: 'command', commands: ['M106 S0'] }) }\">" + gettext("Fan off") + "</button>\
<button class=\"btn \" id=\"fan-lock\" data-bind=\"enable: isOperational() && loginState.isUser(), click: function() { $root.lockFanInput() }, attr: { title: lockTitle } \">\
<i class=\"fa fa-unlock\" data-bind=\"css: {'fa-lock': islocked(), 'fa-unlock': !islocked()}\"></i>\
</button>\
$("#control > div.jog-panel.general").find("button").eq(0).before("\
<input type=\"number\" style=\"width: 90px\" data-bind=\"slider: {min: 00, max: 100, step: 1, value: fanSpeed, tooltip: 'hide'}\">\
<button class=\"btn btn-block control-box\" data-bind=\"enable: isOperational() && !isPrinting() && loginState.isUser(), click: function() { sendFanSpeed() }\">" + gettext("Fan on") + ":<span data-bind=\"text: fanSpeed() + '%'\"></span></button>\
<button class=\"btn btn-block control-box\" data-bind=\"enable: isOperational() && !isPrinting() && loginState.isUser(), click: function() { $root.sendCustomCommand({ type: 'command', commands: ['M106 S0'] }) }\">" + gettext("Fan off") + "</button>\
");
} else { //if TouchUI is active we only add the speed input + fan on button in a new section.
console.log("Fan Speed Slider: NOTICE! TouchUI is active, adding simplified control.");
$("#control > div.jog-panel.general").after("\
<div id=\"control-fan-slider\" class=\"jog-panel filament\" data-bind=\"visible: loginState.isUser\">\
<div>\
<input type=\"number\" style=\"width: 150px\" data-bind=\"slider: {min: 00, max: 255, step: 1, value: fanSpeed, tooltip: 'hide'}\">\
<button class=\"btn btn-block control-box\" data-bind=\"enable: isOperational() && !isPrinting() && loginState.isUser(), click: function() { sendFanSpeed() }\">" + gettext("Fan Speed(%)") + "</button>\
</div>\
</div>\
");
} else {
//replace touch UI's fan on button with one that sends whatever speed is set in this plugin
$("#fan-on").remove();
$("#control-jog-general").find("button").eq(0).after("\
<button class=\"btn btn-block control-box\" id=\"fan-on\" data-bind=\"enable: isOperational() && loginState.isUser(), click: function() { $root.sendFanSpeed() }\">" + gettext("Fan on") + "</button>\
");
//also add spin box + button below in its own section, button is redundant but convenient
$("#control-jog-feedrate").append("\
<input type=\"number\" style=\"width: 150px\" data-bind=\"slider: {min: 00, max: 100, step: 1, value: fanSpeed, tooltip: 'hide'}\">\
<button class=\"btn btn-block\" style=\"width: 169px\" data-bind=\"enable: isOperational() && loginState.isUser() && !islocked(), click: function() { $root.sendFanSpeed() }\">" + gettext("Fan speed:") + "<span data-bind=\"text: fanSpeed() + '%'\"></span></button>\
<button class=\"btn \" id=\"fan-lock\" data-bind=\"enable: isOperational() && loginState.isUser(), click: function() { $root.lockFanInput() }, attr: { title: lockTitle } \">\
Fan Control Lock: <i class=\"fa fa-unlock\" data-bind=\"css: {'fa-lock': islocked(), 'fa-unlock': !islocked()}\"></i>\
</button>\
");
}
//retrieve settings
self.onBeforeBinding = function() {
fanSpeed(self.settings.settings.plugins.fanspeedslider.fanSpeed());
}
}
catch (error) {
console.log(error);
}
OCTOPRINT_VIEWMODELS.push([
FanSliderPluginViewModel,
self.updateSettings = function () {
try {
self.settings.minFanSpeed(parseInt(self.settings.settings.plugins.fanspeedslider.minSpeed()));
self.settings.maxFanSpeed(parseInt(self.settings.settings.plugins.fanspeedslider.maxSpeed()));
self.settings.notifyDelay(parseInt(self.settings.settings.plugins.fanspeedslider.notifyDelay()));
self.settings.lockfan(self.settings.settings.plugins.fanspeedslider.lockfan());
if (self.settings.lockfan()) {
self.control.lockTitle( gettext("Lock or unlock the cooling fan controls. When locked, no cooling fan commands will be sent to the printer. \n\n Fan controls are locked."));
}
else if (!self.settings.lockfan()) {
self.control.lockTitle( gettext("Lock or unlock the cooling fan controls. When locked, no cooling fan commands will be sent to the printer. \n\n Fan controls are unlocked"))
}
self.settings.defaultLastSpeed(self.settings.settings.plugins.fanspeedslider.defaultLastSpeed());
}
catch (error) {
console.log(error);
}
}
self.onBeforeBinding = function () {
self.settings.defaultFanSpeed(parseInt(self.settings.settings.plugins.fanspeedslider.defaultFanSpeed()));
self.settings.lastSentSpeed(parseInt(self.settings.settings.plugins.fanspeedslider.lastSentSpeed()));
self.updateSettings();
//if the default fan speed is above or below max/min then set to either max or min
if (self.settings.defaultFanSpeed() < self.settings.minFanSpeed()) {
self.control.fanSpeed(self.settings.minFanSpeed());
}
else if (self.settings.defaultFanSpeed() > self.settings.maxFanSpeed()) {
self.control.fanSpeed(self.settings.maxFanSpeed());
}
else if (self.settings.defaultLastSpeed()) {
self.control.fanSpeed(self.settings.lastSentSpeed());
}
else {
self.control.fanSpeed(self.settings.defaultFanSpeed());
}
}
//update settings in case user changes them, otherwise a refresh of the UI is required
self.onSettingsHidden = function () {
self.updateSettings();
}
}
OCTOPRINT_VIEWMODELS.push({
construct: FanSliderPluginViewModel,
additionalNames: [],
dependencies: ["settingsViewModel", "controlViewModel", "loginStateViewModel"],
optional: [],
elements: []
});
["printerStateViewModel", "loginStateViewModel", "controlViewModel", "settingsViewModel"]
]);
});

View File

@ -1,66 +1,17 @@
<h3>{{ _('Fan Speed Control') }}</h3>
<h4>{{ _('Fan Speed Slider') }}</h4>
<div>
<p>{{ _('Set the default value for the fan speed slider.') }}</p>
</div>
<div>
<form class="form-horizontal">
<div class="control-group">
<label class="control-label">{{ _('Default Value') }}</label>
<div class="controls">
<div class="input-append">
<input type="number" min="0" max="100" class="input-mini" data-bind="attr: { title: defaultTitle }, value: settings.plugins.fanspeedslider.defaultFanSpeed">
<input type="number" min="0" max="100" class="input-mini" data-bind="value: settings.plugins.fanspeedslider.fanSpeed">
<span class="add-on">%</span>
</div>
<span class="help-block">{{ _('The default value the slider will be set to when opening OctoPrint\'s UI') }}</span>
</div>
</div>
<div class="control-group">
<label class="control-label">{{ _('Remember Last Speed') }}</label>
<div class="controls">
<div class="input-append">
<input type="checkbox" class="input-mini" data-bind="attr: { title: lastspeedTitle }, checked: settings.plugins.fanspeedslider.defaultLastSpeed">
</div>
<span class="help-block">{{ _('Instead of the default speed value, the slider will use the last sent speed as the default value') }}</span>
</div>
</div>
<!--<strong>{{ _('The settings below can be used to limit the fan\'s output without having to re-slice and re-upload your gcode.') }}</strong>-->
<div class="control-group">
<label class="control-label">{{ _('Minimum Speed') }}</label>
<div class="controls">
<div class="input-append">
<input type="number" min="0" max="100" class="input-mini" data-bind="attr: { title: minTitle }, value: settings.plugins.fanspeedslider.minSpeed">
<span class="add-on">%</span>
</div>
<span class="help-block">{{ _('Any value sent which is below this value will be increased to meet this speed. Useful if your fan doesn\'t work below a certain threshold.') }}</span>
</div>
</div>
<div class="control-group">
<label class="control-label">{{ _('Maximum Speed') }}</label>
<div class="controls">
<div class="input-append">
<input type="number" min="0" max="100" class="input-mini" data-bind="attr: { title: maxTitle }, value: settings.plugins.fanspeedslider.maxSpeed">
<span class="add-on">%</span>
</div>
<span class="help-block">{{ _('Any value sent which is above this value will be decreased to meet this speed. Useful if your fan is too strong on full speed.') }}</span>
</div>
</div>
<p><i>{{ _('NOTE: The min/max setting has no effect when you are printing from an SD card that is attached directly to the printer as the gcode does not pass through OctoPrint.') }}</i></p>
<div class="control-group">
<label class="control-label">{{ _('Disable M106 / M107') }}</label>
<div class="controls">
<div class="input-append">
<input type="checkbox" class="input-mini" data-bind="attr: { title: maxTitle }, checked: settings.plugins.fanspeedslider.lockfan">
</div>
<span class="help-block">{{ _('Disables cooling fan commands from reaching the printer. Use with caution. (This performs the same function as the padlock button in the fan section of the controls page)') }}</span>
</div>
</div>
<h3>{{ _('Notification Auto Hide Delay') }}</h3>
<div class="control-group">
<label class="control-label">{{ _('Notification Autohide Delay') }}</label>
<div class="controls">
<div class="input-append">
<input type="number" min="0" class="input-mini" data-bind="attr: {title: noticeTitle }, value: settings.plugins.fanspeedslider.notifyDelay">
<span class="add-on">ms</span>
</div>
<span class="help-block">{{ _('Delay (in milliseconds) before notifications are auto-hidden. Set to 0 to disable notifications.') }}</span>
<span class="help-inline">{{ _('This value does <i><b>not</b></i> affect the maximum or minimum speed of the fan. To limit the power the fan will use during a print, see your slicer\'s min / max fan speed setting.') }}</span>
</div>
</div>
</form>

View File

@ -14,7 +14,7 @@ plugin_package = "octoprint_fanspeedslider"
plugin_name = "OctoPrint-FanSpeedSlider"
# The plugin's version. Can be overwritten within OctoPrint's internal data via __plugin_version__ in the plugin module
plugin_version = "0.2.1"
plugin_version = "0.1.2"
# The plugin's description. Can be overwritten within OctoPrint's internal data via __plugin_description__ in the plugin
# module