update klipper

This commit is contained in:
whb0514
2025-07-29 15:43:51 +08:00
parent 0293507b71
commit f96c748538
7 changed files with 176 additions and 7 deletions

View File

@@ -0,0 +1,110 @@
# Dynamic configuration loader for Klipper
#
# Copyright (C) 2023 Your Name <your.email@example.com>
#
# 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)

View File

@@ -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)

View File

@@ -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
######################################################################

View File

@@ -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)

View File

@@ -21,6 +21,9 @@
# Load "AHT10"
[aht10]
# Load "AHT20_F"
[aht20_f]
# Load "LM75" sensor
[lm75]

View File

@@ -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:

View File

@@ -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
######################################################################