From b3fee62937496f04fd49f07bcb776ad01f405d79 Mon Sep 17 00:00:00 2001 From: sergiuToporjinschi Date: Thu, 3 Feb 2022 09:29:31 +0200 Subject: [PATCH] Refactor message hooking --- octoprint_CalibrationTools/EStepsApi.py | 7 +-- octoprint_CalibrationTools/PIDAutoTune.py | 36 ++++++++++++- octoprint_CalibrationTools/api.py | 17 +++++-- octoprint_CalibrationTools/hooks.py | 50 ++++++++++++------- .../static/js/PIDTuneViewModel.js | 28 ++++++++++- .../templates/tabs/tab-esteps.jinja2 | 6 +-- .../templates/tabs/tab-pid.jinja2 | 2 +- 7 files changed, 112 insertions(+), 34 deletions(-) diff --git a/octoprint_CalibrationTools/EStepsApi.py b/octoprint_CalibrationTools/EStepsApi.py index 31b1e3d..7b5f4be 100644 --- a/octoprint_CalibrationTools/EStepsApi.py +++ b/octoprint_CalibrationTools/EStepsApi.py @@ -22,7 +22,6 @@ class API(octoprint.plugin.SimpleApiPlugin): } def apiGateWay(self, command, data): - self._logger.debug("api command [%s] received payload [%s]", command, data) if command == CMD_ESTEPS_LOAD_STEPS: self._logger.debug("Load steps from EEPROM") if not self._printer.is_ready(): @@ -38,11 +37,11 @@ class API(octoprint.plugin.SimpleApiPlugin): # Issue M92 command self._printer.commands("M92") - m92Event.wait() + m92Event.wait(5) + return flask.jsonify({ "data": self.data["steps"] }) - if command == CMD_ESTEPS_START_EXTRUSION: self._logger.debug("Heating the extruder [%s]", data) if not self._printer.is_ready(): @@ -53,10 +52,8 @@ class API(octoprint.plugin.SimpleApiPlugin): # Register event to be trigger when temp is achieved self.registerEventTemp("T0", int(data["extrudeTemp"]), self.startExtrusion, data["extrudeLength"], data["extrudeSpeed"]) - # Heating the tool self._printer.commands("M104 S%(extrudeTemp)s" % data) - return if command == CMD_ESTEPS_SAVE: eStepsSettings = self._settings.get(['eSteps']) diff --git a/octoprint_CalibrationTools/PIDAutoTune.py b/octoprint_CalibrationTools/PIDAutoTune.py index f7a895d..2de9b14 100644 --- a/octoprint_CalibrationTools/PIDAutoTune.py +++ b/octoprint_CalibrationTools/PIDAutoTune.py @@ -8,17 +8,51 @@ import flask import octoprint.plugin CMD_PID_SAVE = "pid_save" +CMD_PID_START = "pid_start" +regexPID = "Kp:\s*(?P

\d{1,3}.\d{1,3})\s*Ki:\s*(?P\d{1,3}.\d{1,3})\s*Kd:\s*(?P\d{1,3}.\d{1,3})" +regexGetPid = "\s*Kp:\s*(?P

\d{1,3}.\d{1,3})\s*Ki:\s*(?P\d{1,3}.\d{1,3})\s*Kd:\s*(?P\d{1,3}.\d{1,3})" +PIDStarted = "PID Autotune start" +PIDStoped = "PID Autotune finished!" +PIDStopedP = "#define DEFAULT_Kp\s*(?P

\d{1,3}.\d{1,3})" +PIDStopedI = "#define DEFAULT_Ki\s*(?P\d{1,3}.\d{1,3})" +PIDStopedD = "#define DEFAULT_Kd\s*(?P\d{1,3}.\d{1,3})" +regexFinished = "PID Autotune finished!.*\n#define DEFAULT_Kp\s*(?P

\d{1,3}.\d{1,3}).*\n#define DEFAULT_Ki\s*(?P\d{1,3}.\d{1,3})\n#define DEFAULT_Kd\s*(?P\d{1,3}.\d{1,3})" class API(octoprint.plugin.SimpleApiPlugin): @staticmethod def apiCommands(): return { - CMD_PID_SAVE : ["fanSpeed", "noCycles" "hotEndIndex", "targetTemp"] + CMD_PID_SAVE : [], + CMD_PID_START: ["fanSpeed", "noCycles", "hotEndIndex", "targetTemp"] } def apiGateWay(self, command, data): self._logger.debug("DIPGateway") + if command == CMD_PID_START: + self.pidCycles = [] + + for i in range(0,data['noCycles']): + self.registerRegexMsg(regexGetPid, self.m106CodeResponse) + + self._printer.commands(["M106 S%(fanSpeed)s" % data, "M303 C%(noCycles)s E%(hotEndIndex)s S%(targetTemp)s U1" % data]) + self._logger.debug("cycles %s", self.pidCycles) + if command == CMD_PID_SAVE: self._logger.debug("DIPSave-") + return flask.jsonify({ + "data": self.pidCycles + }) + @staticmethod + def m106CodeResponse(self, line): + self._logger.debug("m106CodeResponse: %s", line) + # isM106Response = re.compile(regexFinished).match(line) + # if isM106Response: + # p = isM106Response.group("P") + # i = isM106Response.group("I") + # d = isM106Response.group("D") + # self._logger.debug("P:%s, I:%s, d:%d", p, i, d) + # self._logger.debug("line: %s", line) + self.pidCycles.append(line) + self._logger.debug("cycles %s", self.pidCycles) diff --git a/octoprint_CalibrationTools/api.py b/octoprint_CalibrationTools/api.py index 86d59b4..ccdfe3c 100644 --- a/octoprint_CalibrationTools/api.py +++ b/octoprint_CalibrationTools/api.py @@ -1,6 +1,9 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, division, print_function, unicode_literals +import traceback +from ast import Try + import flask from octoprint_CalibrationTools import EStepsApi, PIDAutoTune @@ -33,7 +36,13 @@ class API(EStepsApi.API, PIDAutoTune.API): ) def on_api_command(self, command, data): - self._logger.debug("API command [%s] received payload [%s]", command, data) - for key, api in self.commandsRegistration.items(): - if command in api["commands"]: - return api["cls"].apiGateWay(self, command, data) + try: + self._logger.debug("API command [%s] received payload [%s]", command, data) + for key, api in self.commandsRegistration.items(): + if command in api["commands"]: + return api["cls"].apiGateWay(self, command, data) + except Exception as e: + self._logger.error(traceback.format_exc()) + return flask.abort(500, { + "msg": "An error curred" + }) diff --git a/octoprint_CalibrationTools/hooks.py b/octoprint_CalibrationTools/hooks.py index 1738668..1272b99 100644 --- a/octoprint_CalibrationTools/hooks.py +++ b/octoprint_CalibrationTools/hooks.py @@ -1,12 +1,11 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, division, print_function, unicode_literals -from ast import arg +import collections import re import threading import traceback import types -import collections class Hooks(): @@ -15,20 +14,26 @@ class Hooks(): gCodeWaiters = [] def gCodeReceived(self, comm, line, *args, **kwargs): - if len(self.gCodeWaiters) <= 0 and not line.startswith('echo:'): - return line - - reg = re.compile("echo:\s*(?PM\d{1,4})") - mCommand = reg.match(line) - if mCommand: - gCode = mCommand.group("gCode") + try: + if len(self.gCodeWaiters) <= 0: + return line for waiter in self.gCodeWaiters: - if gCode.upper() == waiter["cmd"]: - arg = (line, *waiter["args"]) + reg = waiter["regex"] + waiter["callCount"] = waiter["callCount"] + 1 + if reg.match(line): + args = (line, *waiter["args"]) if isinstance(waiter["func"], types.FunctionType): - arg = (self, *arg) - threading.Thread(target=waiter["func"], args=arg).start() - self.gCodeWaiters.remove(waiter) + args = (self, *args) + threading.Thread(target=waiter["func"], args=args).start() + waiter["dead"] = True + break + if waiter["callCount"] >= 3: + self._logger.warning("Hanging thread: Removing waiter regex: %(regex)s" % waiter) + waiter["dead"] = True + self.gCodeWaiters = [w for w in self.gCodeWaiters if "dead" not in w or not w["dead"]] + except Exception as e: + self._logger.error(traceback.format_exc()) + self.gCodeWaiters = [] return line def firmwareInfo(self, comm_instance, firmware_name, firmware_data, *args, **kwargs): @@ -79,11 +84,20 @@ class Hooks(): # Registering a gCodeWaiter def registerGCodeWaiter(self, command, func, *arguments): - if command is None or not re.compile("(?PM\d{1,4})").match(command.upper()) or func is None or not isinstance(func, collections.Callable): - self._logger.warn("registerGCodeAnswer: Attempt to register gCodeAnswer without a function or gCode command") + reg = re.compile(".*\s*(?P[M,G]\d{1,4})") + if command is None or not reg.match(command.upper()): + self._logger.warn("registerGCodeAnswer: Attempt to register gCodeAnswer without a function or valid gCode command") return + self.registerRegexMsg(".*\s*(?P[M,G]\d{1,4})", func, *arguments) + + def registerRegexMsg(self, regex, func, *arguments): + if regex is None or func is None or not isinstance(func, collections.Callable): + self._logger.warn("registerRegexMsg: Attempt to register gCodeAnswer without a function or regex") + return + self.gCodeWaiters.append({ - "cmd": command.upper(), + "regex": re.compile(regex), "func": func, - "args": arguments + "args": arguments, + "callCount": 0 }) diff --git a/octoprint_CalibrationTools/static/js/PIDTuneViewModel.js b/octoprint_CalibrationTools/static/js/PIDTuneViewModel.js index ed45bfe..e835267 100644 --- a/octoprint_CalibrationTools/static/js/PIDTuneViewModel.js +++ b/octoprint_CalibrationTools/static/js/PIDTuneViewModel.js @@ -3,10 +3,11 @@ $(function () { var self = this; self.loginStateViewModel = parameters[0]; self.settingsViewModel = parameters[1]; + self.controlViewModel = parameters[2]; self.bedCurrentTemp = ko.observable(0); self.bedCurrentTarget = ko.observable(0); - self.is_admin = ko.observable(false); + self.isAdmin = ko.observable(false); self.pid = { fanSpeed: ko.observable(255), noCycles: ko.observable(5), @@ -24,7 +25,30 @@ $(function () { self.pid.noCycles(self.settingsViewModel.settings.plugins.CalibrationTools.pid.noCycles()); self.pid.hotEndIndex(self.settingsViewModel.settings.plugins.CalibrationTools.pid.hotEndIndex()); self.pid.targetTemp(self.settingsViewModel.settings.plugins.CalibrationTools.pid.targetTemp()); - self.is_admin(self.loginStateViewModel.isAdmin()); + self.isAdmin(self.loginStateViewModel.isAdmin()); + } + + self.startPidHotEnd = function () { + OctoPrint.simpleApiCommand("CalibrationTools", "pid_start", { + "fanSpeed": self.pid.fanSpeed(), + "noCycles": self.pid.noCycles(), + "hotEndIndex": self.pid.hotEndIndex(), + "targetTemp": self.pid.targetTemp() + }).done(function (response) { + new PNotify({ + title: "PID HotEnd tuning has started", + text: "In progress", + type: "info" + }); + console.log(response); + }).fail(function (response) { + new PNotify({ + title: "Error on starting extrusion ", + text: response.responseJSON.error, + type: "error", + hide: false + }); + }); } } OCTOPRINT_VIEWMODELS.push({ diff --git a/octoprint_CalibrationTools/templates/tabs/tab-esteps.jinja2 b/octoprint_CalibrationTools/templates/tabs/tab-esteps.jinja2 index 1fa6ed5..34d58b0 100644 --- a/octoprint_CalibrationTools/templates/tabs/tab-esteps.jinja2 +++ b/octoprint_CalibrationTools/templates/tabs/tab-esteps.jinja2 @@ -42,7 +42,7 @@

-
- {{ snipped.linkToMarlin("M92", "Marlin website") }} + {{ snipped.linkToMarlin("M092", "Marlin website") }} {{ snipped.m500Icon() }}
@@ -92,7 +92,7 @@
-