Refactor message hooking

This commit is contained in:
sergiuToporjinschi
2022-02-03 09:29:31 +02:00
parent 457bf990db
commit b3fee62937
7 changed files with 112 additions and 34 deletions
+2 -5
View File
@@ -22,7 +22,6 @@ class API(octoprint.plugin.SimpleApiPlugin):
} }
def apiGateWay(self, command, data): def apiGateWay(self, command, data):
self._logger.debug("api command [%s] received payload [%s]", command, data)
if command == CMD_ESTEPS_LOAD_STEPS: if command == CMD_ESTEPS_LOAD_STEPS:
self._logger.debug("Load steps from EEPROM") self._logger.debug("Load steps from EEPROM")
if not self._printer.is_ready(): if not self._printer.is_ready():
@@ -38,11 +37,11 @@ class API(octoprint.plugin.SimpleApiPlugin):
# Issue M92 command # Issue M92 command
self._printer.commands("M92") self._printer.commands("M92")
m92Event.wait() m92Event.wait(5)
return flask.jsonify({ return flask.jsonify({
"data": self.data["steps"] "data": self.data["steps"]
}) })
if command == CMD_ESTEPS_START_EXTRUSION: if command == CMD_ESTEPS_START_EXTRUSION:
self._logger.debug("Heating the extruder [%s]", data) self._logger.debug("Heating the extruder [%s]", data)
if not self._printer.is_ready(): if not self._printer.is_ready():
@@ -53,10 +52,8 @@ class API(octoprint.plugin.SimpleApiPlugin):
# Register event to be trigger when temp is achieved # Register event to be trigger when temp is achieved
self.registerEventTemp("T0", int(data["extrudeTemp"]), self.startExtrusion, data["extrudeLength"], data["extrudeSpeed"]) self.registerEventTemp("T0", int(data["extrudeTemp"]), self.startExtrusion, data["extrudeLength"], data["extrudeSpeed"])
# Heating the tool # Heating the tool
self._printer.commands("M104 S%(extrudeTemp)s" % data) self._printer.commands("M104 S%(extrudeTemp)s" % data)
return
if command == CMD_ESTEPS_SAVE: if command == CMD_ESTEPS_SAVE:
eStepsSettings = self._settings.get(['eSteps']) eStepsSettings = self._settings.get(['eSteps'])
+35 -1
View File
@@ -8,17 +8,51 @@ import flask
import octoprint.plugin import octoprint.plugin
CMD_PID_SAVE = "pid_save" CMD_PID_SAVE = "pid_save"
CMD_PID_START = "pid_start"
regexPID = "Kp:\s*(?P<P>\d{1,3}.\d{1,3})\s*Ki:\s*(?P<I>\d{1,3}.\d{1,3})\s*Kd:\s*(?P<D>\d{1,3}.\d{1,3})"
regexGetPid = "\s*Kp:\s*(?P<p>\d{1,3}.\d{1,3})\s*Ki:\s*(?P<i>\d{1,3}.\d{1,3})\s*Kd:\s*(?P<d>\d{1,3}.\d{1,3})"
PIDStarted = "PID Autotune start"
PIDStoped = "PID Autotune finished!"
PIDStopedP = "#define DEFAULT_Kp\s*(?P<P>\d{1,3}.\d{1,3})"
PIDStopedI = "#define DEFAULT_Ki\s*(?P<I>\d{1,3}.\d{1,3})"
PIDStopedD = "#define DEFAULT_Kd\s*(?P<D>\d{1,3}.\d{1,3})"
regexFinished = "PID Autotune finished!.*\n#define DEFAULT_Kp\s*(?P<P>\d{1,3}.\d{1,3}).*\n#define DEFAULT_Ki\s*(?P<I>\d{1,3}.\d{1,3})\n#define DEFAULT_Kd\s*(?P<D>\d{1,3}.\d{1,3})"
class API(octoprint.plugin.SimpleApiPlugin): class API(octoprint.plugin.SimpleApiPlugin):
@staticmethod @staticmethod
def apiCommands(): def apiCommands():
return { return {
CMD_PID_SAVE : ["fanSpeed", "noCycles" "hotEndIndex", "targetTemp"] CMD_PID_SAVE : [],
CMD_PID_START: ["fanSpeed", "noCycles", "hotEndIndex", "targetTemp"]
} }
def apiGateWay(self, command, data): def apiGateWay(self, command, data):
self._logger.debug("DIPGateway") 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: if command == CMD_PID_SAVE:
self._logger.debug("DIPSave-") 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)
+9
View File
@@ -1,6 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function, unicode_literals from __future__ import absolute_import, division, print_function, unicode_literals
import traceback
from ast import Try
import flask import flask
from octoprint_CalibrationTools import EStepsApi, PIDAutoTune from octoprint_CalibrationTools import EStepsApi, PIDAutoTune
@@ -33,7 +36,13 @@ class API(EStepsApi.API, PIDAutoTune.API):
) )
def on_api_command(self, command, data): def on_api_command(self, command, data):
try:
self._logger.debug("API command [%s] received payload [%s]", command, data) self._logger.debug("API command [%s] received payload [%s]", command, data)
for key, api in self.commandsRegistration.items(): for key, api in self.commandsRegistration.items():
if command in api["commands"]: if command in api["commands"]:
return api["cls"].apiGateWay(self, command, data) 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"
})
+31 -17
View File
@@ -1,12 +1,11 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function, unicode_literals from __future__ import absolute_import, division, print_function, unicode_literals
from ast import arg
import collections
import re import re
import threading import threading
import traceback import traceback
import types import types
import collections
class Hooks(): class Hooks():
@@ -15,20 +14,26 @@ class Hooks():
gCodeWaiters = [] gCodeWaiters = []
def gCodeReceived(self, comm, line, *args, **kwargs): def gCodeReceived(self, comm, line, *args, **kwargs):
if len(self.gCodeWaiters) <= 0 and not line.startswith('echo:'): try:
if len(self.gCodeWaiters) <= 0:
return line return line
reg = re.compile("echo:\s*(?P<gCode>M\d{1,4})")
mCommand = reg.match(line)
if mCommand:
gCode = mCommand.group("gCode")
for waiter in self.gCodeWaiters: for waiter in self.gCodeWaiters:
if gCode.upper() == waiter["cmd"]: reg = waiter["regex"]
arg = (line, *waiter["args"]) waiter["callCount"] = waiter["callCount"] + 1
if reg.match(line):
args = (line, *waiter["args"])
if isinstance(waiter["func"], types.FunctionType): if isinstance(waiter["func"], types.FunctionType):
arg = (self, *arg) args = (self, *args)
threading.Thread(target=waiter["func"], args=arg).start() threading.Thread(target=waiter["func"], args=args).start()
self.gCodeWaiters.remove(waiter) 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 return line
def firmwareInfo(self, comm_instance, firmware_name, firmware_data, *args, **kwargs): def firmwareInfo(self, comm_instance, firmware_name, firmware_data, *args, **kwargs):
@@ -79,11 +84,20 @@ class Hooks():
# Registering a gCodeWaiter # Registering a gCodeWaiter
def registerGCodeWaiter(self, command, func, *arguments): def registerGCodeWaiter(self, command, func, *arguments):
if command is None or not re.compile("(?P<gCode>M\d{1,4})").match(command.upper()) or func is None or not isinstance(func, collections.Callable): reg = re.compile(".*\s*(?P<gCode>[M,G]\d{1,4})")
self._logger.warn("registerGCodeAnswer: Attempt to register gCodeAnswer without a function or gCode command") 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 return
self.registerRegexMsg(".*\s*(?P<gCode>[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({ self.gCodeWaiters.append({
"cmd": command.upper(), "regex": re.compile(regex),
"func": func, "func": func,
"args": arguments "args": arguments,
"callCount": 0
}) })
@@ -3,10 +3,11 @@ $(function () {
var self = this; var self = this;
self.loginStateViewModel = parameters[0]; self.loginStateViewModel = parameters[0];
self.settingsViewModel = parameters[1]; self.settingsViewModel = parameters[1];
self.controlViewModel = parameters[2];
self.bedCurrentTemp = ko.observable(0); self.bedCurrentTemp = ko.observable(0);
self.bedCurrentTarget = ko.observable(0); self.bedCurrentTarget = ko.observable(0);
self.is_admin = ko.observable(false); self.isAdmin = ko.observable(false);
self.pid = { self.pid = {
fanSpeed: ko.observable(255), fanSpeed: ko.observable(255),
noCycles: ko.observable(5), noCycles: ko.observable(5),
@@ -24,7 +25,30 @@ $(function () {
self.pid.noCycles(self.settingsViewModel.settings.plugins.CalibrationTools.pid.noCycles()); self.pid.noCycles(self.settingsViewModel.settings.plugins.CalibrationTools.pid.noCycles());
self.pid.hotEndIndex(self.settingsViewModel.settings.plugins.CalibrationTools.pid.hotEndIndex()); self.pid.hotEndIndex(self.settingsViewModel.settings.plugins.CalibrationTools.pid.hotEndIndex());
self.pid.targetTemp(self.settingsViewModel.settings.plugins.CalibrationTools.pid.targetTemp()); 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({ OCTOPRINT_VIEWMODELS.push({
@@ -42,7 +42,7 @@
<div class="row-fluid" style="margin-bottom: 5px;"> <div class="row-fluid" style="margin-bottom: 5px;">
<div class="span6"></div> <div class="span6"></div>
<div class="span6"> <div class="span6">
<button class="btn btn-success" data-bind="click: $root.startExtrusion, enable: $root.controlViewModel.isOperational() && (!$root.controlViewModel.isPrinting())" <button class="btn btn-success" data-bind="click: $root.startExtrusion, enable: $root.is_admin() && $root.controlViewModel.isOperational() && (!$root.controlViewModel.isPrinting())"
title="This will trigger M90, M83, G1 E100 F50, M82, G90 in order for extruding filament"> title="This will trigger M90, M83, G1 E100 F50, M82, G90 in order for extruding filament">
<i class="fas fa-play" style="color:false" data-color="false"></i>&nbsp&nbsp <i class="fas fa-play" style="color:false" data-color="false"></i>&nbsp&nbsp
Start extrusion Start extrusion
@@ -82,7 +82,7 @@
</div> </div>
<div class="span6"> <div class="span6">
<div class="input-prepend input-append"> <div class="input-prepend input-append">
{{ snipped.linkToMarlin("M92", "Marlin website") }} {{ snipped.linkToMarlin("M092", "Marlin website") }}
<span class="add-on" title="Command to change number of steps/mm for E axe" data-bind="text: $root.results.newStepsDisplay"></span> <span class="add-on" title="Command to change number of steps/mm for E axe" data-bind="text: $root.results.newStepsDisplay"></span>
{{ snipped.m500Icon() }} {{ snipped.m500Icon() }}
</div> </div>
@@ -92,7 +92,7 @@
<div class="row-fluid" style="margin-bottom: 5px;"> <div class="row-fluid" style="margin-bottom: 5px;">
<div class="span6"></div> <div class="span6"></div>
<div class="span6"> <div class="span6">
<button class="btn btn-primary" data-bind="click: $root.saveESteps, enable: $root.controlViewModel.isOperational() && (!$root.controlViewModel.isPrinting())" <button class="btn btn-primary" data-bind="click: $root.saveESteps, enable: $root.is_admin() && $root.controlViewModel.isOperational() && (!$root.controlViewModel.isPrinting())"
title="Saves the new calculated value of steps/mm on printer EEPROM"> title="Saves the new calculated value of steps/mm on printer EEPROM">
<i class="fas fa-save" data-color="#000000"></i>&nbsp&nbsp <i class="fas fa-save" data-color="#000000"></i>&nbsp&nbsp
Save the new value Save the new value
@@ -42,7 +42,7 @@ Current bed temperature: <span data-bind="text: bedCurrentTemp"></span>&#176; Be
<div class="row-fluid" style="margin-bottom: 5px;"> <div class="row-fluid" style="margin-bottom: 5px;">
<div class="span5"></div> <div class="span5"></div>
<div class="span7"> <div class="span7">
<button class="btn btn-success" data-bind="click: $root.pidHotEndTune, enable: $root.controlViewModel.isOperational() && (!$root.controlViewModel.isPrinting())" <button class="btn btn-success" data-bind="click: $root.startPidHotEnd, enable: $root.controlViewModel.isOperational() && (!$root.controlViewModel.isPrinting())"
title="This will trigger PID auto tuning (M106 Sx; M303 Ex Sx U1; M500)"> title="This will trigger PID auto tuning (M106 Sx; M303 Ex Sx U1; M500)">
<i class="fas fa-play" style="color:false" data-color="false"></i>&nbsp&nbsp <i class="fas fa-play" style="color:false" data-color="false"></i>&nbsp&nbsp
Start PID tunning Start PID tunning