Skip to content

Commit 82d192f

Browse files
committed
Add klipper service restart button
1 parent 1827962 commit 82d192f

File tree

3 files changed

+81
-6
lines changed

3 files changed

+81
-6
lines changed

octoprint_moonraker_connector/__init__.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from urllib.parse import urljoin
44

55
import requests
6+
import subprocess
67
from flask import jsonify
78
from flask_babel import gettext
89

@@ -72,6 +73,7 @@ def _configure_json_rpc_logging(self):
7273
def get_settings_defaults(self):
7374
return {
7475
"emergency_stop_on_cancel": False,
76+
"restart_klipper_service_command": "sudo systemctl restart klipper.service",
7577
}
7678

7779
##~~ SimpleApiPlugin
@@ -93,6 +95,24 @@ def on_api_get(self, request):
9395
)
9496
return jsonify(response.model_dump(by_alias=True))
9597

98+
def get_api_commands(self):
99+
return dict(
100+
restart_klipper_service=[]
101+
)
102+
103+
def on_api_command(self, command, data):
104+
if command == 'restart_klipper_service':
105+
configured_command = self._settings.get(["restart_klipper_service_command"])
106+
107+
try:
108+
# Use subprocess.Popen for a non-blocking execution
109+
subprocess.Popen(configured_command, shell=True)
110+
return jsonify({"status": "executed", "command": configured_command})
111+
except Exception as e:
112+
return jsonify({"status": "error", "message": str(e)}), 500
113+
114+
return jsonify({"status": "error", "message": "Invalid command"}), 400
115+
96116
def is_api_protected(self):
97117
return True
98118

octoprint_moonraker_connector/static/clientjs/moonraker_connector.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
return this.base.simpleApiGet("moonraker_connector", opts);
1414
};
1515

16+
OctoPrintMoonrakerConnectorClient.prototype.command = function (command, payload) {
17+
return this.base.simpleApiCommand("moonraker_connector", command, payload);
18+
};
19+
1620
OctoPrintClient.registerPluginComponent(
1721
"moonraker_connector",
1822
OctoPrintMoonrakerConnectorClient

octoprint_moonraker_connector/static/js/moonraker_connector.js

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,30 @@ $(function () {
1515
OctoPrint.control.sendGcode('FIRMWARE_RESTART');
1616
}
1717

18+
self.btnKlipperRestartClick = function() {
19+
showConfirmationDialog({
20+
message: gettext("<strong>This will restart the Klipper service.</strong></p><p>This might disrupt any ongoing operations related to Klipper."),
21+
onproceed: function() {
22+
// Execute the registered system command
23+
OctoPrint.plugins.moonraker_connector.command({
24+
command: 'restart_klipper_service'
25+
}).done(function(response) {
26+
new PNotify({
27+
title: gettext("Success"),
28+
text: gettext("System command sent: ") + response.command,
29+
type: "success"
30+
});
31+
}).fail(function(jqXHR, textStatus, errorThrown) {
32+
new PNotify({
33+
title: gettext("Error"),
34+
text: gettext("Failed to execute command: ") + jqXHR.responseJSON.message,
35+
type: "error"
36+
});
37+
});
38+
}
39+
});
40+
}
41+
1842
self.initializeButton = function() {
1943
var buttonContainer = $('#job_print')[0].parentElement;
2044
var container = document.createElement("div");
@@ -24,39 +48,66 @@ $(function () {
2448

2549
var btnRestart = document.createElement("button");
2650
btnRestart.id = "job_restart";
27-
btnRestart.title = "Reload configuration file and performs an internal reset of the host software. It does not clear the error state from the micro-controller.";
51+
btnRestart.title = gettext("Reload configuration file and performs an internal reset of the host software. It does not clear the error state from the micro-controller.");
2852
btnRestart.classList.add("btn");
2953
btnRestart.classList.add("span6");
3054
btnRestart.addEventListener("click", self.btnRestartClick);
3155

3256
var btnRestartIcon = document.createElement("i");
33-
btnRestartIcon.classList.add("fa", "fa-redo");
57+
btnRestartIcon.classList.add("fas", "fa-sync-alt");
58+
btnRestartIcon.style.marginRight = "5px";
3459
btnRestart.appendChild(btnRestartIcon);
3560

3661
var btnRestartText = document.createElement("span");
37-
btnRestartText.textContent = " Restart";
62+
btnRestartText.textContent = gettext("Restart");
3863
btnRestart.appendChild(btnRestartText);
3964

4065
container.appendChild(btnRestart);
4166

4267
var btnFirmwareRestart = document.createElement("button");
4368
btnFirmwareRestart.id = "job_firmware_restart";
44-
btnFirmwareRestart.title = "Reload configuration file and performs an internal reset of the host software, but it also clears any error states from the micro-controller.";
69+
btnFirmwareRestart.title = gettext("Reload configuration file and performs an internal reset of the host software, but it also clears any error states from the micro-controller.");
4570
btnFirmwareRestart.classList.add("btn");
4671
btnFirmwareRestart.classList.add("span6");
4772
btnFirmwareRestart.addEventListener("click", self.btnFirmwareRestartClick);
4873

4974
var btnFirmwareRestartIcon = document.createElement("i");
50-
btnFirmwareRestartIcon.classList.add("fa", "fa-sync");
75+
btnFirmwareRestartIcon.classList.add("fas", "fa-microchip");
76+
btnFirmwareRestartIcon.style.marginRight = "5px";
5177
btnFirmwareRestart.appendChild(btnFirmwareRestartIcon);
5278

5379
var btnFirmwareRestartText = document.createElement("span");
54-
btnFirmwareRestartText.textContent = " Firmware Restart";
80+
btnFirmwareRestartText.textContent = gettext("Firmware Restart");
5581
btnFirmwareRestart.appendChild(btnFirmwareRestartText);
5682

5783
container.appendChild(btnFirmwareRestart);
5884

5985
buttonContainer.after(container);
86+
87+
var container2 = document.createElement("div");
88+
container2.classList.add("row-fluid", "print-control");
89+
container2.style.marginTop = "10px";
90+
container2.setAttribute("data-bind", "visible: $root.loginState.hasPermissionKo($root.access.permissions.PRINT)");
91+
92+
var btnKlipperRestart = document.createElement("button");
93+
btnKlipperRestart.id = "job_klipper_restart";
94+
btnKlipperRestart.title = gettext("Restart klipper process.");
95+
btnKlipperRestart.classList.add("btn");
96+
btnKlipperRestart.classList.add("span12");
97+
btnKlipperRestart.addEventListener("click", self.btnKlipperRestartClick);
98+
99+
var btnKlipperRestartIcon = document.createElement("i");
100+
btnKlipperRestartIcon.classList.add("fas", "fa-power-off");
101+
btnKlipperRestartIcon.style.marginRight = "5px";
102+
btnKlipperRestart.appendChild(btnKlipperRestartIcon);
103+
104+
var btnKlipperRestartText = document.createElement("span");
105+
btnKlipperRestartText.textContent = gettext("Restart Klipper");
106+
btnKlipperRestart.appendChild(btnKlipperRestartText);
107+
108+
container2.appendChild(btnKlipperRestart);
109+
110+
container.after(container2);
60111
};
61112

62113
self.webcams = ko.observableArray([]);

0 commit comments

Comments
 (0)