Merge branch 'devel' into rc

This commit is contained in:
thelastWallE 2021-04-07 00:09:56 +02:00
commit fcc73166e8
13 changed files with 377 additions and 254 deletions

View File

@ -21,4 +21,4 @@ indent_size = 2
indent_size = 2
[**.jinja2]
indent_size = 3
indent_size = 2

View File

@ -1,7 +1,7 @@
## Fork information:
- This is forked from [the original](https://github.com/mmone/OctoprintKlipperPlugin) version 0.2.5
- The fork now supports Python3 (hopefully without any new bugs)
- The current version is 0.3.4rc1 and includes the pull requests left on the old plugin page that fixes several bugs and Themify support.
- The current version is 0.3.5 and includes the pull requests left on the old plugin page that fixes several bugs and Themify support.
## Fork Installation Information:
- Uninstall any other versions of the plugin using Plugin Manager or other means, as necessary.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 226 KiB

After

Width:  |  Height:  |  Size: 226 KiB

View File

@ -32,6 +32,9 @@ try:
except ImportError:
import ConfigParser as configparser
if sys.version_info[0] < 3:
import StringIO
class KlipperPlugin(
octoprint.plugin.StartupPlugin,
octoprint.plugin.TemplatePlugin,
@ -41,7 +44,7 @@ class KlipperPlugin(
octoprint.plugin.EventHandlerPlugin):
_parsing_response = False
_parsing_check_response = False
_parsing_check_response = True
_message = ""
def __init__(self):
@ -125,7 +128,8 @@ class KlipperPlugin(
old_config="",
logpath="/tmp/klippy.log",
reload_command="RESTART",
navbar=True
navbar=True,
parse_check=False
)
)
@ -157,7 +161,11 @@ class KlipperPlugin(
)
if "config" in data:
try:
if self.key_exist(data, "configuration", "parse_check"):
check_parse = data["configuration"]["parse_check"]
else:
check_parse = self._settings.get(["configuration", "parse_check"])
if sys.version_info[0] < 3:
data["config"] = data["config"].encode('utf-8')
@ -171,18 +179,29 @@ class KlipperPlugin(
configpath = os.path.expanduser(
self._settings.get(["configuration", "configpath"])
)
if self.file_exist(configpath) and self._parsing_check_response:
if self.file_exist(configpath) and (self._parsing_check_response or not check_parse):
try:
f = open(configpath, "w")
f.write(data["config"])
f.close()
# Restart klippy to reload config
self._printer.commands(self._settings.get(
["configuration", "reload_command"]))
self.log_info("Reloading Klipper Configuration.")
self.log_debug("Writing Klipper config to {}".format(configpath))
except IOError:
self.log_error("Error: Couldn't write Klipper config file: {}".format(configpath))
else:
#load the reload command from changed data if it is not existing load the saved setting
if self.key_exist(data, "configuration", "reload_command"):
reload_command = os.path.expanduser(
data["configuration"]["reload_command"]
)
else:
reload_command = self._settings.get(["configuration", "reload_command"])
if reload_command != "manually":
# Restart klippy to reload config
self._printer.commands(reload_command)
self.log_info("Restarting Klipper.")
# we dont want to write the klipper conf to the octoprint settings
data.pop("config", None)
@ -355,21 +374,31 @@ class KlipperPlugin(
if "FIRMWARE_VERSION" in printerInfo:
self.log_info("Firmware version: {}".format(
printerInfo["FIRMWARE_VERSION"]))
elif "// probe" in line:
msg = line.strip('/')
self.log_info(msg)
write_parsing_response_buffer()
elif "//" in line:
# add lines with // to a buffer
self._message = self._message + line.strip('/')
if not self._parsing_response:
self.update_status("info", self._message)
self._parsing_response = True
elif "!!" in line:
msg = line.strip('!')
self.update_status("error", msg)
self.log_error(msg)
self.write_parsing_response_buffer()
else:
self.write_parsing_response_buffer()
return line
def write_parsing_response_buffer(self):
# write buffer with // lines after a gcode response without //
if self._parsing_response:
self._parsing_response = False
self.log_info(self._message)
self._message = ""
if "!!" in line:
msg = line.strip('!')
self.update_status("error", msg)
self.log_error(msg)
return line
def get_api_commands(self):
return dict(
@ -419,17 +448,21 @@ class KlipperPlugin(
configpath)
)
else:
self._settings.set(["config"], data["config"])
# self.send_message("reload", "config", "", data["config"])
# send the configdata to frontend to update ace editor
if sys.version_info[0] < 3:
data["config"] = data["config"].decode('utf-8')
return flask.jsonify(data=data["config"])
elif command == "checkConfig":
if "config" in data:
if not self.validate_configfile(data["config"]):
self.log_debug("validateConfig ->" + data["config"])
self.log_debug("validateConfig not ok")
self._settings.set(["configuration", "old_config"], data["config"])
return flask.jsonify(checkConfig="not OK")
else:
self.log_debug("validateConfig ok")
self._settings.set(["configuration", "old_config"], "")
return flask.jsonify(checkConfig="OK")
@ -479,7 +512,6 @@ class KlipperPlugin(
def log_info(self, message):
self._octoklipper_logger.info(message)
self.send_message("log", "info", message, message)
self.send_message("console", "info", message, message)
def log_debug(self, message):
self._octoklipper_logger.debug(message)
@ -490,7 +522,6 @@ class KlipperPlugin(
def log_error(self, error):
self._octoklipper_logger.error(error)
self.send_message("log", "error", error, error)
self.send_message("console", "error", error, error)
def file_exist(self, filepath):
if not os.path.isfile(filepath):
@ -529,23 +560,33 @@ class KlipperPlugin(
# learn file to be validated
try:
dataToValidated = configparser.RawConfigParser()
dataToValidated = configparser.RawConfigParser(strict=False)
#
if sys.version_info[0] < 3:
buf = StringIO.StringIO(dataToBeValidated)
dataToValidated.readfp(buf)
else:
dataToValidated.read_string(dataToBeValidated)
except configparser.Error as error:
if sys.version_info[0] < 3:
error.message = error.message.replace("\\n","")
error.message = error.message.replace("file: u","Klipper Configuration", 1)
error.message = error.message.replace("'","", 2)
error.message = error.message.replace("u'","'", 1)
else:
error.message = error.message.replace("\\n","")
error.message = error.message.replace("file:","Klipper Configuration", 1)
error.message = error.message.replace("'","", 2)
error.source = "Klipper config"
self.log_error(
"Error: Invalid Klipper config file:\n" +
"{}".format(str(error))
)
self.send_message("PopUp", "warning", "Invalid Config",
self.send_message("PopUp", "warning", "OctoKlipper: Invalid Config data\n",
"Config got not saved!\n" +
"You can reload your last changes\n" +
"on the 'Klipper Configuration' tab.\n\n" + str(error))
self._parsing_check_response = False
return
else:
self._parsing_check_response = True
return

View File

@ -113,6 +113,14 @@ div#settings_plugin_klipper.tab-pane.active form.form-horizontal div.tab-content
margin: 0px 2px 2px 2px;
}
div#settings_plugin_klipper.tab-pane.active form.form-horizontal div.tab-content div#conf.tab-pane.active div.control-group label.inline input.inline-checkbox {
vertical-align:-0.2em;
}
div#settings_plugin_klipper.tab-pane.active form.form-horizontal div.tab-content div#conf.tab-pane.active div.control-group label.inline {
display:inline;
}
#macros #item.control-group {
margin-bottom: 2px;
border: 2px solid #ccc;

View File

@ -16,7 +16,6 @@
$(function () {
function KlipperViewModel(parameters) {
var self = this;
var console_debug = false;
self.header = OctoPrint.getRequestHeaders({
"content-type": "application/json",
@ -145,6 +144,7 @@ $(function () {
break;
default:
self.logMessage(data.time, data.subtype, data.payload);
self.consoleMessage(data.subtype, data.payload);
}
//if ("warningPopUp" == data.type){
@ -165,7 +165,11 @@ $(function () {
}
};
self.logMessage = function (timestamp, type, message) {
self.logMessage = function (timestamp, type="info", message) {
if (!timestamp) {
var today = new Date();
var timestamp = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
}
self.logMessages.push({
time: timestamp,
type: type,
@ -174,15 +178,15 @@ $(function () {
};
self.consoleMessage = function (type, message) {
if (self.settings.settings.plugins.klipper.configuration.debug_logging() === true) {
if (type == "info"){
console.info("OctoKlipper : " + message);
} else if (type == "debug"){
if (console_debug){
console.debug("OctoKlipper : " + message);
}
} else {
console.error("OctoKlipper : " + message);
}
}
return
};
@ -200,7 +204,7 @@ $(function () {
$.ajax(settings).done(function (response) {
self.consoleMessage(
"debug",
"Reloaded from Backend " + response);
"Reloaded config file from Backend");
});
}

View File

@ -13,38 +13,64 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
$(function() {
$(function () {
function KlipperOffsetDialogViewModel(parameters) {
var self = this;
self.klipperViewModel = parameters[0];
self.offsetX = ko.observable();
self.offsetY = ko.observable();
self.offsetZ = ko.observable();
self.adjust = ko.observable();
self.onStartup = function() {
self.onStartup = function () {
self.offsetX(0);
self.offsetY(0);
self.offsetZ(0);
self.adjust(false);
}
};
self.setOffset = function() {
if(self.adjust()) {
OctoPrint.control.sendGcode("SET_GCODE_OFFSET X_ADJUST=" + self.offsetX() +
" Y_ADJUST=" + self.offsetY() +
" Z_ADJUST=" + self.offsetZ());
self.setOffset = function () {
if (self.adjust()) {
self.klipperViewModel.logMessage("","info", "SET_GCODE_OFFSET\n X_ADJUST=" +
self.offsetX() +
" Y_ADJUST=" +
self.offsetY() +
" Z_ADJUST=" +
self.offsetZ())
OctoPrint.control.sendGcode(
"SET_GCODE_OFFSET X_ADJUST=" +
self.offsetX() +
" Y_ADJUST=" +
self.offsetY() +
" Z_ADJUST=" +
self.offsetZ()
);
} else {
OctoPrint.control.sendGcode("SET_GCODE_OFFSET X=" + self.offsetX() +
" Y=" + self.offsetY() +
" Z=" + self.offsetZ());
}
self.klipperViewModel.logMessage("","info", "SET_GCODE_OFFSET\n X=" +
self.offsetX() +
" Y=" +
self.offsetY() +
" Z=" +
self.offsetZ())
OctoPrint.control.sendGcode(
"SET_GCODE_OFFSET X=" +
self.offsetX() +
" Y=" +
self.offsetY() +
" Z=" +
self.offsetZ()
);
}
};
}
OCTOPRINT_VIEWMODELS.push({
construct: KlipperOffsetDialogViewModel,
dependencies: [],
elements: ["#klipper_offset_dialog"]
dependencies: ["klipperViewModel"],
elements: ["#klipper_offset_dialog"],
});
});

View File

@ -21,6 +21,7 @@ $(function() {
var editor = null;
self.settings = parameters[0];
self.klipperViewModel = parameters[1];
self.header = OctoPrint.getRequestHeaders({
"content-type": "application/json",
@ -30,8 +31,8 @@ $(function() {
self.apiUrl = OctoPrint.getSimpleApiUrl("klipper");
self.onSettingsBeforeSave = function () {
if (editor.session) {
//console.debug("OctoKlipper : onSettingsBeforeSave:" + editor.session.getValue())
if (editor.session && self.settings.settings.plugins.klipper.configuration.parse_check() === true) {
self.klipperViewModel.consoleMessage("debug", "onSettingsBeforeSave:")
var settings = {
"crossDomain": true,
"url": self.apiUrl,
@ -108,7 +109,7 @@ $(function() {
self.loadLastSession = function () {
if (self.settings.settings.plugins.klipper.configuration.old_config() != "") {
console.debug("OctoKlipper : lastSession:" + self.settings.settings.plugins.klipper.configuration.old_config())
self.klipperViewModel.consoleMessage("info","lastSession:" + self.settings.settings.plugins.klipper.configuration.old_config())
if (editor.session) {
editor.session.setValue(self.settings.settings.plugins.klipper.configuration.old_config());
editor.clearSelection();
@ -194,7 +195,10 @@ $(function() {
OCTOPRINT_VIEWMODELS.push({
construct: KlipperSettingsViewModel,
dependencies: ["settingsViewModel"],
dependencies: [
"settingsViewModel",
"klipperViewModel"
],
elements: ["#settings_plugin_klipper"]
});
});

View File

@ -60,7 +60,7 @@ ace.define("ace/mode/klipper_config_highlight_rules",[], function(require, expor
regex: /^\[/,
push: [{
token: "text",
regex: /\]\s*$/,
regex: /\]/,
next: "pop"
}, {
include: "#known_config_block_name"

View File

@ -28,7 +28,7 @@
</div>
<div class="control-group">
<div class="controls">
<button class="btn btn-block" data-bind="click: setOffset"><i class="icon-cross"></i> {{ _('Set Offset') }}</button>
<button class="btn btn-block" data-bind="click: setOffset" data-dismiss="modal"><i class="icon-cross"></i> {{ _('Set Offset') }}</button>
</div>
</div>
</div>

View File

@ -50,9 +50,11 @@
<select data-bind="value: settings.settings.plugins.klipper.configuration.reload_command">
<option value="RESTART">RESTART</option>
<option value="FIRMWARE_RESTART">FIRMWARE_RESTART</option>
<option value="manually">Manually</option>
</select>
<span class="help-block">
The command that is executed when the Klipper configuration changed and needs to be reloaded.
The command that is executed when the Klipper configuration changed and needs to be reloaded.<br>
Set this to "Manually" if you don't want to immediately restart klipper.
</span>
</div>
</div>
@ -207,9 +209,11 @@
<button class="btn btn-small" data-bind='click: loadLastSession'
title="Reloads the last changes">
<i class="fas fa-redo"></i> {{ _('Reload last changes') }}
</button><button class="btn btn-small" data-bind='click: reloadFromFile'>
</button>
<button class="btn btn-small" data-bind='click: reloadFromFile'>
<i class="fas fa-upload"></i></a> {{ _('Reload from file') }}
</button>
<label class="inline"><input class="inline-checkbox" type="checkbox" data-bind="checked: settings.settings.plugins.klipper.configuration.parse_check"> {{ _('Check parsing on save') }}</label>
<div class="conf-editor">
<input id="hdnLoadKlipperConfig" type="hidden" data-bind="value: configBound(settings.settings.plugins.klipper.config)" />
<div id="plugin-klipper-config"></div>

View File

@ -1,8 +1,6 @@
<div class="row-fluid">
<div class="span8">
<label>
<i class="icon-tasks"></i> {{ _('Messages') }}
</label>
<label> <i class="icon-tasks"></i> {{ _("Messages") }} </label>
<div class="plugin-klipper-log" data-bind="foreach: logMessages">
<div class="log-item" data-bind="css: type">
<div data-bind="text: time" class="ts"></div>
@ -10,9 +8,12 @@
</div>
</div>
&nbsp;
<button class="btn btn-mini pull-right clear-btn" data-bind="click: onClearLog"
title="Clear Log">
<i class="fa fa-trash"></i> {{ _('Clear') }}
<button
class="btn btn-mini pull-right clear-btn"
data-bind="click: onClearLog"
title="Clear Log"
>
<i class="fa fa-trash"></i> {{ _("Clear") }}
</button>
</div>
<div class="span4">
@ -20,54 +21,89 @@
<div class="control-group">
<div class="controls">
<label class="control-label"></label>
<button class="btn btn-block btn-small" data-bind="click: onGetStatus, enable: isActive()" title="Query Klipper for its current status">
<i class="fa icon-black fa-info-circle"></i> {{ _('Get Status') }}
<button
class="btn btn-block btn-small"
data-bind="click: onGetStatus, enable: isActive()"
title="Query Klipper for its current status"
>
<i class="fa icon-black fa-info-circle"></i> {{ _("Get Status") }}
</button>
<button class="btn btn-block btn-small" data-bind="visible: hasRight('CONFIG', 'Ko'), click: function() {openOctoKlipperSettings('klipper-config');}" title="Open the Klipper configurationfile">
<i class="fa icon-black fa-file-code-o"></i> {{ _('Open Klipper config') }}
<button
class="btn btn-block btn-small"
data-bind="visible: hasRight('CONFIG', 'Ko'), click: function() {openOctoKlipperSettings('klipper-config');}"
title="Open the Klipper configurationfile"
>
<i class="fa icon-black fa-file-code-o"></i>
{{ _("Open Klipper config") }}
</button>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="control-label small"><i class="icon-refresh"></i> {{ _('Restart') }}</label>
<button class="btn btn-block btn-small" data-bind="click: onRestartHost, enable: isActive()"
title="This will cause the host software to reload its config and perform an internal reset">
{{ _('Host') }}
<label class="control-label small"
><i class="icon-refresh"></i> {{ _("Restart") }}</label
>
<button
class="btn btn-block btn-small"
data-bind="click: onRestartHost, enable: isActive()"
title="This will cause the host software to reload its config and perform an internal reset"
>
{{ _("Host") }}
</button>
<button class="btn btn-block btn-small" data-bind="click: onRestartFirmware, enable: isActive()"
title="Similar to a host restart, but also clears any error state from the micro-controller">
{{ _('Firmware') }}
<button
class="btn btn-block btn-small"
data-bind="click: onRestartFirmware, enable: isActive()"
title="Similar to a host restart, but also clears any error state from the micro-controller"
>
{{ _("Firmware") }}
</button>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="control-label"><i class="icon-wrench"></i> {{ _('Tools') }}</label>
<button class="btn btn-block btn-small" data-bind="click: showLevelingDialog, enable: isActive()"
title="Assists in manually leveling your printbed by moving the head to a configurable set of positions in sequence.">
{{ _('Assisted Bed Leveling') }}
<label class="control-label"
><i class="icon-wrench"></i> {{ _("Tools") }}</label
>
<button
class="btn btn-block btn-small"
data-bind="click: showLevelingDialog, enable: isActive()"
title="Assists in manually leveling your printbed by moving the head to a configurable set of positions in sequence."
>
{{ _("Assisted Bed Leveling") }}
</button>
<button class="btn btn-block btn-small" data-bind="click: showPidTuningDialog, enable: isActive()"
title="Determines optimal PID parameters by heat cycling the hotend/bed.">
{{ _('PID Tuning') }}
<button
class="btn btn-block btn-small"
data-bind="click: showPidTuningDialog, enable: isActive()"
title="Determines optimal PID parameters by heat cycling the hotend/bed."
>
{{ _("PID Tuning") }}
</button>
<button class="btn btn-block btn-small" data-bind="click: showOffsetDialog, enable: isActive()"
title="Sets a offset for subsequent GCODE coordinates.">
{{ _('Coordinate Offset') }}
<button
class="btn btn-block btn-small"
data-bind="click: showOffsetDialog, enable: isActive()"
title="Sets a offset for subsequent GCODE coordinates."
>
{{ _("Coordinate Offset") }}
</button>
<button class="btn btn-block btn-small" data-bind="click: showGraphDialog"
title="Assists in debugging performance issues by analyzing the Klipper log files.">
{{ _('Analyze Klipper Log') }}
<button
class="btn btn-block btn-small"
data-bind="click: showGraphDialog"
title="Assists in debugging performance issues by analyzing the Klipper log files."
>
{{ _("Analyze Klipper Log") }}
</button>
</div>
</div>
<div class="controls" data-bind="visible: hasRight('MACRO', 'Ko')">
<label class="control-label"><i class="icon-list-alt"></i> {{ _('Macros') }}</label>
<label class="control-label"
><i class="icon-list-alt"></i> {{ _("Macros") }}</label
>
<div data-bind="foreach: settings.settings.plugins.klipper.macros">
<!-- ko if: tab -->
<button class="btn btn-block btn-small" data-bind="text: name, click: $parent.executeMacro, enable: $parent.isActive()">
</button>
<button
class="btn btn-block btn-small"
data-bind="text: name, click: $parent.executeMacro, enable: $parent.isActive()"
></button>
<!-- /ko -->
</div>
</div>

View File

@ -19,7 +19,7 @@ plugin_package = "octoprint_klipper"
plugin_name = "OctoKlipper"
plugin_version = "0.3.4rc5"
plugin_version = "0.3.7.2"
plugin_description = """A plugin for OctoPrint to configure,control and monitor the Klipper 3D printer software."""