2018-01-23 17:01:58 +03:00
|
|
|
# coding=utf-8
|
|
|
|
from __future__ import absolute_import
|
2018-01-23 21:30:55 +03:00
|
|
|
import datetime
|
2018-01-23 17:01:58 +03:00
|
|
|
import logging
|
|
|
|
import octoprint.plugin
|
|
|
|
import octoprint.plugin.core
|
2018-02-08 18:38:48 +03:00
|
|
|
from octoprint.util.comm import parse_firmware_line
|
2018-08-09 03:16:07 +03:00
|
|
|
import flask
|
2018-01-23 17:01:58 +03:00
|
|
|
|
|
|
|
class KlipperPlugin(
|
|
|
|
octoprint.plugin.StartupPlugin,
|
|
|
|
octoprint.plugin.TemplatePlugin,
|
|
|
|
octoprint.plugin.SettingsPlugin,
|
2018-02-08 18:38:48 +03:00
|
|
|
octoprint.plugin.AssetPlugin,
|
|
|
|
octoprint.plugin.EventHandlerPlugin):
|
2018-02-02 14:39:06 +03:00
|
|
|
|
2018-02-02 18:58:37 +03:00
|
|
|
_parsingResponse = False
|
2018-02-02 16:05:21 +03:00
|
|
|
_message = ""
|
2018-02-08 18:38:48 +03:00
|
|
|
|
2018-08-09 03:16:07 +03:00
|
|
|
#-- Startup Plugin
|
2018-01-23 17:01:58 +03:00
|
|
|
|
|
|
|
def on_after_startup(self):
|
2018-02-02 16:05:21 +03:00
|
|
|
klipperPort = self._settings.get(["serialport"])
|
|
|
|
additionalPorts = self._settings.global_get(["serial", "additionalPorts"])
|
|
|
|
|
|
|
|
if klipperPort not in additionalPorts:
|
|
|
|
additionalPorts.append(klipperPort)
|
|
|
|
self._settings.global_set(["serial", "additionalPorts"], additionalPorts)
|
|
|
|
self._settings.save()
|
2018-08-09 03:16:07 +03:00
|
|
|
self._logger.info("Added klipper serial port {} to list of additional ports.".format(klipperPort))
|
2018-02-02 16:05:21 +03:00
|
|
|
|
2018-02-02 14:39:06 +03:00
|
|
|
#-- Settings Plugin
|
2018-08-09 03:16:07 +03:00
|
|
|
|
2018-01-23 17:01:58 +03:00
|
|
|
def get_settings_defaults(self):
|
|
|
|
return dict(
|
|
|
|
serialport="/tmp/printer",
|
|
|
|
replace_connection_panel=True,
|
2018-01-25 01:49:11 +03:00
|
|
|
macros=[{'name':"E-Stop", 'macro':"M112", 'sidebar':True, 'tab':True}],
|
2018-01-23 23:31:43 +03:00
|
|
|
probeHeight=0,
|
2018-01-24 19:15:48 +03:00
|
|
|
probeLift=5,
|
2018-01-24 22:54:13 +03:00
|
|
|
probeSpeedXy=1500,
|
2018-01-24 21:05:28 +03:00
|
|
|
probeSpeedZ=500,
|
2018-08-09 03:16:07 +03:00
|
|
|
probePoints=[{'x':0, 'y':0}],
|
|
|
|
configPath="/home/pi/printer.cfg"
|
|
|
|
)
|
|
|
|
|
|
|
|
def on_settings_load(self):
|
|
|
|
data = octoprint.plugin.SettingsPlugin.on_settings_load(self)
|
|
|
|
f = open(self._settings.get(["configPath"]), "r")
|
|
|
|
if f:
|
|
|
|
data["config"] = f.read()
|
|
|
|
f.close()
|
|
|
|
else:
|
|
|
|
self._logger.info(
|
|
|
|
"Error: Klipper config file not found at: {}".format(self._settings.get(["configPath"]))
|
|
|
|
)
|
|
|
|
return data
|
|
|
|
|
|
|
|
def on_settings_save(self, data):
|
|
|
|
if "config" in data:
|
|
|
|
f = open(self._settings.get(["configPath"]), "w")
|
|
|
|
if f:
|
|
|
|
f.write(data["config"])
|
|
|
|
f.close()
|
|
|
|
self._logger.info(
|
|
|
|
"Write Klipper config to {}".format(self._settings.get(["configPath"]))
|
|
|
|
)
|
|
|
|
# Restart klipply to reload config
|
|
|
|
self._printer.commands("RESTART")
|
|
|
|
self.logInfo("Reloading Klipper Configuration.")
|
|
|
|
else:
|
|
|
|
self._logger.info(
|
|
|
|
"Error: Couldn't write Klipper config file: {}".format(self._settings.get(["configPath"]))
|
|
|
|
)
|
|
|
|
data.pop('config', None) # we dont want to write the klipper conf to the octoprint settings
|
|
|
|
else:
|
|
|
|
octoprint.plugin.SettingsPlugin.on_settings_save(self, data)
|
|
|
|
|
|
|
|
def get_settings_restricted_paths(self):
|
|
|
|
return dict(
|
|
|
|
admin=[
|
|
|
|
["serialport"],
|
|
|
|
["configPath"],
|
|
|
|
["replace_connection_panel"]
|
|
|
|
],
|
|
|
|
user=[
|
|
|
|
["macros"],
|
|
|
|
["probeHeight"],
|
|
|
|
["probeLift"],
|
|
|
|
["probeSpeedXy"],
|
|
|
|
["probeSpeedZ"],
|
|
|
|
["probePoints"]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
2018-02-02 14:39:06 +03:00
|
|
|
#-- Template Plugin
|
2018-08-09 03:16:07 +03:00
|
|
|
|
2018-01-23 17:01:58 +03:00
|
|
|
def get_template_configs(self):
|
|
|
|
return [
|
2018-02-08 18:38:48 +03:00
|
|
|
dict(type="navbar", custom_bindings=True),
|
2018-01-23 17:01:58 +03:00
|
|
|
dict(type="settings", custom_bindings=True),
|
2018-01-24 19:15:48 +03:00
|
|
|
dict(type="generic", name="Assisted Bed Leveling", template="klipper_leveling_dialog.jinja2", custom_bindings=True),
|
2018-04-26 22:06:09 +03:00
|
|
|
dict(type="generic", name="PID Tuning", template="klipper_pid_tuning_dialog.jinja2", custom_bindings=True),
|
|
|
|
dict(type="generic", name="Coordinate Offset", template="klipper_offset_dialog.jinja2", custom_bindings=True),
|
2018-01-24 19:15:48 +03:00
|
|
|
dict(type="tab", name="Klipper", template="klipper_tab_main.jinja2", suffix="_main", custom_bindings=True),
|
2018-01-23 17:01:58 +03:00
|
|
|
dict(type="sidebar",
|
|
|
|
custom_bindings=True,
|
2018-08-03 06:34:17 +03:00
|
|
|
icon="rocket",
|
2018-02-02 14:39:06 +03:00
|
|
|
replaces= "connection" if self._settings.get_boolean(["replace_connection_panel"]) else "")
|
2018-01-23 17:01:58 +03:00
|
|
|
]
|
|
|
|
|
2018-02-02 14:39:06 +03:00
|
|
|
#-- Asset Plugin
|
|
|
|
|
2018-01-23 17:01:58 +03:00
|
|
|
def get_assets(self):
|
|
|
|
return dict(
|
2018-01-24 19:15:48 +03:00
|
|
|
js=["js/klipper.js",
|
|
|
|
"js/klipper_settings.js",
|
|
|
|
"js/klipper_leveling.js",
|
2018-04-26 22:06:09 +03:00
|
|
|
"js/klipper_pid_tuning.js",
|
|
|
|
"js/klipper_offset.js"],
|
2018-01-23 17:01:58 +03:00
|
|
|
css=["css/klipper.css"],
|
|
|
|
less=["css/klipper.less"]
|
|
|
|
)
|
2018-01-23 20:33:22 +03:00
|
|
|
|
2018-02-08 18:38:48 +03:00
|
|
|
#-- Event Handler Plugin
|
|
|
|
|
|
|
|
def on_event(self, event, payload):
|
|
|
|
if "Connecting" == event:
|
|
|
|
self.updateStatus("info", "Connecting ...")
|
|
|
|
elif "Connected" == event:
|
2018-02-26 13:46:33 +03:00
|
|
|
self.updateStatus("info", "Connected to host")
|
2018-08-09 03:16:07 +03:00
|
|
|
self.logInfo("Connected to host via {} @{}bps".format(payload["port"], payload["baudrate"]))
|
2018-02-08 18:38:48 +03:00
|
|
|
elif "Disconnected" == event:
|
2018-02-26 13:46:33 +03:00
|
|
|
self.updateStatus("info", "Disconnected from host")
|
2018-02-08 18:38:48 +03:00
|
|
|
elif "Error" == event:
|
|
|
|
self.updateStatus("error", "Error")
|
|
|
|
self.logError(payload["error"])
|
|
|
|
|
2018-02-02 14:39:06 +03:00
|
|
|
#-- GCODE Hook
|
|
|
|
|
|
|
|
def on_parse_gcode(self, comm, line, *args, **kwargs):
|
2018-02-08 18:38:48 +03:00
|
|
|
if "FIRMWARE_VERSION" in line:
|
|
|
|
printerInfo = parse_firmware_line(line)
|
|
|
|
if "FIRMWARE_VERSION" in printerInfo:
|
2018-08-09 03:16:07 +03:00
|
|
|
self.logInfo("Firmware version: {}".format(printerInfo["FIRMWARE_VERSION"]))
|
2018-02-08 18:38:48 +03:00
|
|
|
elif "//" in line:
|
2018-02-02 23:51:24 +03:00
|
|
|
self._message = self._message + line.strip('/')
|
2018-08-09 03:16:07 +03:00
|
|
|
if not self._parsingResponse:
|
|
|
|
self.updateStatus("info", self._message)
|
|
|
|
self._parsingResponse = True
|
2018-02-02 14:39:06 +03:00
|
|
|
else:
|
2018-02-02 18:58:37 +03:00
|
|
|
if self._parsingResponse:
|
2018-08-09 03:16:07 +03:00
|
|
|
self._parsingResponse = False
|
|
|
|
self.logInfo(self._message)
|
|
|
|
self._message = ""
|
2018-02-02 14:39:06 +03:00
|
|
|
if "!!" in line:
|
2018-08-09 03:16:07 +03:00
|
|
|
msg = line.strip('!')
|
|
|
|
self.updateStatus("error", msg)
|
|
|
|
self.logError(msg)
|
2018-02-02 14:39:06 +03:00
|
|
|
return line
|
2018-02-08 18:38:48 +03:00
|
|
|
|
2018-02-02 14:39:06 +03:00
|
|
|
#-- Helpers
|
2018-02-08 18:38:48 +03:00
|
|
|
def sendMessage(self, type, subtype, payload):
|
2018-01-23 21:30:55 +03:00
|
|
|
self._plugin_manager.send_plugin_message(
|
|
|
|
self._identifier,
|
|
|
|
dict(
|
2018-02-02 18:58:37 +03:00
|
|
|
time=datetime.datetime.now().strftime("%H:%M:%S"),
|
2018-02-08 18:38:48 +03:00
|
|
|
type=type, payload=payload)
|
|
|
|
)
|
2018-01-23 20:33:22 +03:00
|
|
|
|
2018-02-26 13:46:33 +03:00
|
|
|
def pollStatus(self):
|
|
|
|
self._printer.commands("STATUS")
|
|
|
|
|
2018-02-08 18:38:48 +03:00
|
|
|
def updateStatus(self, type, status):
|
|
|
|
self.sendMessage("status", type, status)
|
|
|
|
|
|
|
|
def logInfo(self, message):
|
|
|
|
self.sendMessage("log", "info", message)
|
2018-02-02 14:39:06 +03:00
|
|
|
|
2018-02-08 18:38:48 +03:00
|
|
|
def logError(self, error):
|
2018-03-22 22:21:53 +03:00
|
|
|
self.sendMessage("log", "error", error)
|
2018-02-02 14:39:06 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
2018-01-23 17:01:58 +03:00
|
|
|
|
|
|
|
__plugin_name__ = "Klipper"
|
|
|
|
|
|
|
|
def __plugin_load__():
|
|
|
|
global __plugin_implementation__
|
|
|
|
global __plugin_hooks__
|
|
|
|
|
|
|
|
__plugin_implementation__ = KlipperPlugin()
|
|
|
|
__plugin_hooks__ = {
|
2018-02-08 18:38:48 +03:00
|
|
|
"octoprint.comm.protocol.gcode.received": __plugin_implementation__.on_parse_gcode
|
2018-01-23 17:01:58 +03:00
|
|
|
}
|
|
|
|
|