From b3fb0fcd8d6404aa16bcdc0fff88444b72c4d619 Mon Sep 17 00:00:00 2001 From: Chad Condon Date: Sat, 27 Jul 2024 12:52:51 -0700 Subject: [PATCH] Implement show_macros_in_webui --- autospeed/dummy_macros.cfg | 18 +++++++++++ autospeed/main.py | 63 ++++++++++++++++++++++++++++---------- 2 files changed, 64 insertions(+), 17 deletions(-) create mode 100644 autospeed/dummy_macros.cfg diff --git a/autospeed/dummy_macros.cfg b/autospeed/dummy_macros.cfg new file mode 100644 index 0000000..c69b30d --- /dev/null +++ b/autospeed/dummy_macros.cfg @@ -0,0 +1,18 @@ +# This file is used when the `show_macros_in_webui` option is enabled. It wraps +# the native Python commands in macros so that they will show up in web UIs +# like Mainsail and Fluidd. + +[gcode_macro AUTO_SPEED] +gcode: _AUTO_SPEED {rawparams} + +[gcode_macro AUTO_SPEED_VELOCITY] +gcode: _AUTO_SPEED_VELOCITY {rawparams} + +[gcode_macro AUTO_SPEED_ACCEL] +gcode: _AUTO_SPEED_ACCEL {rawparams} + +[gcode_macro AUTO_SPEED_VALIDATE] +gcode: _AUTO_SPEED_VALIDATE {rawparams} + +[gcode_macro AUTO_SPEED_GRAPH] +gcode: _AUTO_SPEED_GRAPH diff --git a/autospeed/main.py b/autospeed/main.py index 287d0a3..0bfcdc2 100644 --- a/autospeed/main.py +++ b/autospeed/main.py @@ -50,6 +50,8 @@ def __init__(self, config): self.validate_inner_margin = config.getfloat('validate_inner_margin', default=20.0, above=0.0) self.validate_iterations = config.getint( 'validate_iterations', default=50, minval=1) + show_macros = config.getboolean('show_macros_in_webui', default=False) + for path in ( # Could be problematic if neither of these paths work os.path.dirname(self.printer.start_args['log_file']), os.path.expanduser('~/printer_data/config') @@ -62,22 +64,49 @@ def __init__(self, config): self.printer.register_event_handler("klippy:connect", self.handle_connect) self.printer.register_event_handler("homing:home_rails_end", self.handle_home_rails_end) - self.gcode.register_command('AUTO_SPEED', - self.cmd_AUTO_SPEED, - desc=self.cmd_AUTO_SPEED_help) - self.gcode.register_command('AUTO_SPEED_VELOCITY', - self.cmd_AUTO_SPEED_VELOCITY, - desc=self.cmd_AUTO_SPEED_VELOCITY_help) - self.gcode.register_command('AUTO_SPEED_ACCEL', - self.cmd_AUTO_SPEED_ACCEL, - desc=self.cmd_AUTO_SPEED_ACCEL_help) - self.gcode.register_command('AUTO_SPEED_VALIDATE', - self.cmd_AUTO_SPEED_VALIDATE, - desc=self.cmd_AUTO_SPEED_VALIDATE_help) - self.gcode.register_command('AUTO_SPEED_GRAPH', - self.cmd_AUTO_SPEED_GRAPH, - desc=self.cmd_AUTO_SPEED_GRAPH_help) - + measurement_commands = [ + ('AUTO_SPEED', self.cmd_AUTO_SPEED, self.cmd_AUTO_SPEED_help), + ('AUTO_SPEED_VELOCITY', self.cmd_AUTO_SPEED_VELOCITY, self.cmd_AUTO_SPEED_VELOCITY_help), + ('AUTO_SPEED_ACCEL', self.cmd_AUTO_SPEED_ACCEL, self.cmd_AUTO_SPEED_ACCEL_help), + ('AUTO_SPEED_VALIDATE', self.cmd_AUTO_SPEED_VALIDATE, self.cmd_AUTO_SPEED_VALIDATE_help), + ('AUTO_SPEED_GRAPH', self.cmd_AUTO_SPEED_GRAPH, self.cmd_AUTO_SPEED_GRAPH_help), + ] + command_descriptions = {name: desc for name, _, desc in measurement_commands} + gcode = self.printer.lookup_object('gcode') + for name, command, description in measurement_commands: + gcode.register_command(f'_{name}' if show_macros else name, command, desc=description) + + # Load the dummy macros with their description in order to show them in the web interfaces + if show_macros: + pconfig = self.printer.lookup_object('configfile') + dirname = os.path.dirname(os.path.realpath(__file__)) + filename = os.path.join(dirname, 'dummy_macros.cfg') + try: + dummy_macros_cfg = pconfig.read_config(filename) + except Exception as err: + raise config.error(f'Cannot load AutoSpeed dummy macro {filename}') from err + + for gcode_macro in dummy_macros_cfg.get_prefix_sections('gcode_macro '): + gcode_macro_name = gcode_macro.get_name() + + # Replace the dummy description by the one here (to avoid code duplication and define it in only one place) + command = gcode_macro_name.split(' ', 1)[1] + description = command_descriptions.get(command, 'AutoSpeed macro') + gcode_macro.fileconfig.set(gcode_macro_name, 'description', description) + + # Add the section to the Klipper configuration object with all its options + if not config.fileconfig.has_section(gcode_macro_name.lower()): + config.fileconfig.add_section(gcode_macro_name.lower()) + for option in gcode_macro.fileconfig.options(gcode_macro_name): + value = gcode_macro.fileconfig.get(gcode_macro_name, option) + config.fileconfig.set(gcode_macro_name.lower(), option, value) + + # Small trick to ensure the new injected sections are considered valid by Klipper config system + config.access_tracking[(gcode_macro_name.lower(), option.lower())] = 1 + + # Finally, load the section within the printer objects + self.printer.load_object(config, gcode_macro_name.lower()) + self.level = None self.steppers = {} @@ -752,4 +781,4 @@ def _set_velocity(self, velocity: float, accel: float): self.toolhead.max_velocity = velocity self.toolhead.max_accel = accel self.toolhead.requested_accel_to_decel = accel/2 - self.toolhead._calc_junction_deviation() \ No newline at end of file + self.toolhead._calc_junction_deviation()