mirror of
https://github.com/QIDITECH/klipper.git
synced 2026-01-30 23:48:43 +03:00
update klipper
This commit is contained in:
110
klippy/extras/dynamaic_config_loader.py
Normal file
110
klippy/extras/dynamaic_config_loader.py
Normal 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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
######################################################################
|
||||
|
||||
@@ -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)
|
||||
@@ -21,6 +21,9 @@
|
||||
# Load "AHT10"
|
||||
[aht10]
|
||||
|
||||
# Load "AHT20_F"
|
||||
[aht20_f]
|
||||
|
||||
# Load "LM75" sensor
|
||||
[lm75]
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
######################################################################
|
||||
|
||||
Reference in New Issue
Block a user