From f96c748538a3474020de1a48d9e4cea59c31522d Mon Sep 17 00:00:00 2001 From: whb0514 <112596503+whb0514@users.noreply.github.com> Date: Tue, 29 Jul 2025 15:43:51 +0800 Subject: [PATCH] update klipper --- klippy/extras/dynamaic_config_loader.py | 110 ++++++++++++++++++++++++ klippy/extras/filament_motion_sensor.py | 9 ++ klippy/extras/heaters.py | 10 ++- klippy/extras/save_variables.py | 40 ++++++++- klippy/extras/temperature_sensors.cfg | 3 + klippy/gcode.py | 2 +- klippy/klippy.py | 9 +- 7 files changed, 176 insertions(+), 7 deletions(-) create mode 100644 klippy/extras/dynamaic_config_loader.py diff --git a/klippy/extras/dynamaic_config_loader.py b/klippy/extras/dynamaic_config_loader.py new file mode 100644 index 0000000..8c1c583 --- /dev/null +++ b/klippy/extras/dynamaic_config_loader.py @@ -0,0 +1,110 @@ +# Dynamic configuration loader for Klipper +# +# Copyright (C) 2023 Your Name +# +# This file may be distributed under the terms of the GNU GPLv3 license. + +import logging +import configparser +import importlib +import os + +class DynamicConfigLoader: + def __init__(self, config): + self.printer = config.get_printer() + self.config_path = config.get('config_path') + self.loaded_configs = {} + + # 注册命令 + gcode = self.printer.lookup_object('gcode') + gcode.register_command('LOAD_CONFIG', self.cmd_LOAD_CONFIG, + desc="动态加载配置文件") + gcode.register_command('UNLOAD_CONFIG', self.cmd_UNLOAD_CONFIG, + desc="卸载动态加载的配置") + gcode.register_command('LIST_LOADED_CONFIGS', self.cmd_LIST_LOADED_CONFIGS, + desc="列出所有已加载的动态配置") + + # 在printer对象初始化完成后加载默认配置 + self.printer.register_event_handler("klippy:connect", self.handle_connect) + + def handle_connect(self): + if self.config_path and os.path.exists(self.config_path): + self._load_config_file(self.config_path) + + def _load_config_file(self, config_path): + try: + config_parser = configparser.ConfigParser() + config_parser.read(config_path) + + for section in config_parser.sections(): + module_name = section.split()[0] + + # 尝试导入模块 + try: + module = importlib.import_module('extras.' + module_name) + if hasattr(module, 'load_config'): + # 创建配置对象 + config_obj = self.printer.lookup_object('configfile').create_config_wrapper( + config_parser, section) + # 调用模块的load_config函数 + obj = module.load_config(config_obj) + if obj is not None: + # 将对象添加到printer + self.printer.add_object(section, obj) + self.loaded_configs[section] = { + 'module': module_name, + 'object': obj + } + logging.info("动态加载配置: %s", section) + except ImportError: + logging.warning("无法导入模块 %s", module_name) + except Exception as e: + logging.exception("加载配置 %s 时出错: %s", section, str(e)) + + return True + except Exception as e: + logging.exception("加载配置文件 %s 时出错: %s", config_path, str(e)) + return False + + def cmd_LOAD_CONFIG(self, gcmd): + config_path = gcmd.get('PATH') + if not os.path.exists(config_path): + raise gcmd.error("配置文件不存在: %s" % config_path) + + success = self._load_config_file(config_path) + if success: + gcmd.respond_info("成功加载配置文件: %s" % config_path) + else: + raise gcmd.error("加载配置文件失败: %s" % config_path) + + def cmd_UNLOAD_CONFIG(self, gcmd): + section = gcmd.get('SECTION') + if section not in self.loaded_configs: + raise gcmd.error("未找到已加载的配置: %s" % section) + + # 从printer中移除对象 + try: + # 某些对象可能需要特殊的清理逻辑 + obj = self.loaded_configs[section]['object'] + if hasattr(obj, 'shutdown'): + obj.shutdown() + + # 从loaded_configs中移除 + del self.loaded_configs[section] + gcmd.respond_info("成功卸载配置: %s" % section) + except Exception as e: + logging.exception("卸载配置 %s 时出错: %s", section, str(e)) + raise gcmd.error("卸载配置失败: %s" % section) + + def cmd_LIST_LOADED_CONFIGS(self, gcmd): + if not self.loaded_configs: + gcmd.respond_info("没有动态加载的配置") + return + + msg = "已加载的动态配置:\n" + for section, info in self.loaded_configs.items(): + msg += " %s (模块: %s)\n" % (section, info['module']) + gcmd.respond_info(msg) + +def load_config(config): + return DynamicConfigLoader(config) \ No newline at end of file diff --git a/klippy/extras/filament_motion_sensor.py b/klippy/extras/filament_motion_sensor.py index fb886aa..192915a 100644 --- a/klippy/extras/filament_motion_sensor.py +++ b/klippy/extras/filament_motion_sensor.py @@ -27,6 +27,7 @@ class EncoderSensor: self.estimated_print_time = None # Initialise internal state self.filament_runout_pos = None + self.button_state = 0 # Register commands and event handlers self.printer.register_event_handler('klippy:ready', self._handle_ready) @@ -36,12 +37,19 @@ class EncoderSensor: self._handle_not_printing) self.printer.register_event_handler('idle_timeout:idle', self._handle_not_printing) + self.gcode = self.printer.lookup_object('gcode') + self.gcode.register_command( + 'CLEAR_MOTION_DATA', + self.cmd_CLEAR_MOTION_DATA + ) def _update_filament_runout_pos(self, eventtime=None): if eventtime is None: eventtime = self.reactor.monotonic() self.filament_runout_pos = ( self._get_extruder_pos(eventtime) + self.detection_length) + def cmd_CLEAR_MOTION_DATA(self, gcmd): + self._update_filament_runout_pos() def _handle_ready(self): self.extruder = self.printer.lookup_object(self.extruder_name) self.estimated_print_time = ( @@ -69,6 +77,7 @@ class EncoderSensor: def encoder_event(self, eventtime, state): if self.extruder is not None: self._update_filament_runout_pos(eventtime) + self.button_state = state # Check for filament insertion # Filament is always assumed to be present on an encoder event self.runout_helper.note_filament_present(True) diff --git a/klippy/extras/heaters.py b/klippy/extras/heaters.py index b8860c4..edd4dd2 100644 --- a/klippy/extras/heaters.py +++ b/klippy/extras/heaters.py @@ -11,7 +11,7 @@ import os, logging, threading ###################################################################### KELVIN_TO_CELSIUS = -273.15 -MAX_HEAT_TIME = 5.0 +MAX_HEAT_TIME = 10.0 AMBIENT_TEMP = 25. PID_PARAM_BASE = 255. @@ -65,6 +65,7 @@ class Heater: gcode.register_mux_command("SET_HEATER_TEMPERATURE", "HEATER", self.name, self.cmd_SET_HEATER_TEMPERATURE, desc=self.cmd_SET_HEATER_TEMPERATURE_help) + self.can_wait = True def set_pwm(self, read_time, value): if self.target_temp <= 0.: value = 0. @@ -166,7 +167,12 @@ class Heater: msg = "The hotbed temperature is too low, and it will automatically heat up to " + str((temp+self.heat_with_heater_bed_tem_add)) gcmd.respond_info(msg) else: - pheaters.set_temperature(self, temp) + wait = bool(gcmd.get_int('WAIT', 0)) + if not self.can_wait: + wait = False + pheaters.set_temperature(self, temp, wait) + def set_can_wait(self, value): + self.can_wait = value ###################################################################### diff --git a/klippy/extras/save_variables.py b/klippy/extras/save_variables.py index 5d6b61c..3e7c9e4 100644 --- a/klippy/extras/save_variables.py +++ b/klippy/extras/save_variables.py @@ -11,6 +11,28 @@ class SaveVariables: self.printer = config.get_printer() self.filename = os.path.expanduser(config.get('filename')) self.allVariables = {} + + self.default_values = { + 'auto_reload_detect': 0, 'auto_read_rfid': 0, 'auto_init_detect': 0, + 'box_count': 0, 'enable_box': 0,'load_retry_num': 0, + 'slot_sync': "", 'retry_step': "", 'last_load_slot': "" + } + + for i in range(16): + self.default_values[f'filament_slot{i}'] = 0 + self.default_values[f'color_slot{i}'] = 0 + self.default_values[f'vendor_slot{i}'] = 0 + self.default_values[f'slot{i}'] = 0 + self.default_values[f'value_t{i}'] = "" + self.default_values[f'runout_{i}'] = 0 + + self.default_values['filament_slot16'] = 0 + self.default_values['color_slot16'] = 0 + self.default_values['vendor_slot16'] = 0 + + for key, value in self.default_values.items(): + setattr(self, key, value) + try: if not os.path.exists(self.filename): open(self.filename, "w").close() @@ -20,6 +42,7 @@ class SaveVariables: gcode = self.printer.lookup_object('gcode') gcode.register_command('SAVE_VARIABLE', self.cmd_SAVE_VARIABLE, desc=self.cmd_SAVE_VARIABLE_help) + def load_variable(self, section, option): varfile = configparser.ConfigParser() try: @@ -29,6 +52,7 @@ class SaveVariables: msg = "Unable to parse existing variable file" logging.exception(msg) raise self.printer.command_error(msg) + def save_variable(self, section, option, value): varfile = configparser.ConfigParser() try: @@ -43,6 +67,7 @@ class SaveVariables: logging.exception(msg) raise self.printer.command_error(msg) self.loadVariables() + def loadVariables(self): allvars = {} varfile = configparser.ConfigParser() @@ -56,7 +81,12 @@ class SaveVariables: logging.exception(msg) raise self.printer.command_error(msg) self.allVariables = allvars + + for key, default in self.default_values.items(): + setattr(self, key, self.allVariables.get(key, default)) + cmd_SAVE_VARIABLE_help = "Save arbitrary variables to disk" + def cmd_SAVE_VARIABLE(self, gcmd): varname = gcmd.get('VARIABLE') value = gcmd.get('VALUE') @@ -80,8 +110,14 @@ class SaveVariables: logging.exception(msg) raise gcmd.error(msg) self.loadVariables() + def get_status(self, eventtime): - return {'variables': self.allVariables} + status = {'variables': self.allVariables} + + for key in self.default_values.keys(): + status[key] = getattr(self, key) + + return status def load_config(config): - return SaveVariables(config) + return SaveVariables(config) \ No newline at end of file diff --git a/klippy/extras/temperature_sensors.cfg b/klippy/extras/temperature_sensors.cfg index 96aa996..5bf301e 100644 --- a/klippy/extras/temperature_sensors.cfg +++ b/klippy/extras/temperature_sensors.cfg @@ -21,6 +21,9 @@ # Load "AHT10" [aht10] +# Load "AHT20_F" +[aht20_f] + # Load "LM75" sensor [lm75] diff --git a/klippy/gcode.py b/klippy/gcode.py index bacbeaa..c3985fb 100644 --- a/klippy/gcode.py +++ b/klippy/gcode.py @@ -358,7 +358,7 @@ class GCodeDispatch: not gcmd.get_float('S', 1.) or self.is_fileinput)): # Don't warn about requests to turn off fan when fan not present return - gcmd.respond_info('Unknown command:"%s"' % (cmd,)) + #gcmd.respond_info('Unknown command:"%s"' % (cmd,)) def _cmd_mux(self, command, gcmd): key, values = self.mux_commands[command] if None in values: diff --git a/klippy/klippy.py b/klippy/klippy.py index 097cff9..29f2685 100644 --- a/klippy/klippy.py +++ b/klippy/klippy.py @@ -7,6 +7,8 @@ import sys, os, gc, optparse, logging, time, collections, importlib import util, reactor, queuelogger, msgproto import gcode, configfile, pins, mcu, toolhead, webhooks +from extras import box_detect +import pyudev, shutil, configparser message_ready = "Printer is ready" @@ -112,9 +114,10 @@ class Printer: module_name = module_parts[0] py_name = os.path.join(os.path.dirname(__file__), 'extras', module_name + '.py') + so_name = os.path.join(os.path.dirname(__file__), 'extras', module_name + '.so') py_dirname = os.path.join(os.path.dirname(__file__), 'extras', module_name, '__init__.py') - if not os.path.exists(py_name) and not os.path.exists(py_dirname): + if not os.path.exists(py_name) and not os.path.exists(so_name) and not os.path.exists(py_dirname): if default is not configfile.sentinel: return default raise self.config_error("Unable to load module '%s'" % (section,)) @@ -139,6 +142,8 @@ class Printer: m.add_printer_objects(config) for section_config in config.get_prefix_sections(''): self.load_object(config, section_config.get_name(), None) + for m in [box_detect]: + m.add_printer_objects(config) for m in [toolhead]: m.add_printer_objects(config) # Validate that there are no undefined parameters in the config file @@ -172,6 +177,7 @@ class Printer: return "\n".join(msg) def _connect(self, eventtime): try: + box_detect.monitor_serial_devices(self) self._read_config() self.send_event("klippy:mcu_identify") for cb in self.event_handlers.get("klippy:connect", []): @@ -266,7 +272,6 @@ class Printer: self.run_result = result self.reactor.end() - ###################################################################### # Startup ######################################################################