mirror of
https://github.com/dw-0/kiauh.git
synced 2026-02-04 16:37:45 +05:00
Compare commits
2 Commits
fix/KIA-77
...
v6.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09a5d96b63 | ||
|
|
1f9d4c823a |
28
kiauh/extensions/tmc_autotune/__init__.py
Normal file
28
kiauh/extensions/tmc_autotune/__init__.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# ======================================================================= #
|
||||||
|
# Copyright (C) 2020 - 2026 Dominik Willner <th33xitus@gmail.com> #
|
||||||
|
# #
|
||||||
|
# This file is part of KIAUH - Klipper Installation And Update Helper #
|
||||||
|
# https://github.com/dw-0/kiauh #
|
||||||
|
# #
|
||||||
|
# This file may be distributed under the terms of the GNU GPLv3 license #
|
||||||
|
# ======================================================================= #
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# repo
|
||||||
|
TMCA_REPO = "https://github.com/andrewmcgr/klipper_tmc_autotune"
|
||||||
|
|
||||||
|
# directories
|
||||||
|
TMCA_DIR = Path.home().joinpath("klipper_tmc_autotune")
|
||||||
|
MODULE_PATH = Path(__file__).resolve().parent
|
||||||
|
KLIPPER_DIR = Path.home().joinpath("klipper")
|
||||||
|
KLIPPER_EXTRAS = KLIPPER_DIR.joinpath("klippy/extras")
|
||||||
|
KLIPPER_PLUGINS = KLIPPER_DIR.joinpath("klippy/plugins")
|
||||||
|
KLIPPER_EXTENSIONS_PATH = (
|
||||||
|
KLIPPER_PLUGINS if KLIPPER_PLUGINS.is_dir() else KLIPPER_EXTRAS
|
||||||
|
)
|
||||||
|
|
||||||
|
# files
|
||||||
|
TMCA_EXAMPLE_CONFIG = TMCA_DIR.joinpath("docs/example.cfg")
|
||||||
|
|
||||||
|
# names
|
||||||
|
TMCA_MOONRAKER_UPDATER_NAME = "update_manager klipper_tmc_autotune"
|
||||||
13
kiauh/extensions/tmc_autotune/metadata.json
Normal file
13
kiauh/extensions/tmc_autotune/metadata.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"index": 13,
|
||||||
|
"module": "tmc_autotune_extension",
|
||||||
|
"maintained_by": "theogayar",
|
||||||
|
"display_name": "Klipper TMC Autotune",
|
||||||
|
"description": [
|
||||||
|
"Klipper extension for automatic configuration and tuning of TMC drivers."
|
||||||
|
],
|
||||||
|
"repo": "https://github.com/andrewmcgr/klipper_tmc_autotune",
|
||||||
|
"updates": true
|
||||||
|
}
|
||||||
|
}
|
||||||
384
kiauh/extensions/tmc_autotune/tmc_autotune_extension.py
Normal file
384
kiauh/extensions/tmc_autotune/tmc_autotune_extension.py
Normal file
@@ -0,0 +1,384 @@
|
|||||||
|
# ======================================================================= #
|
||||||
|
# Copyright (C) 2020 - 2026 Dominik Willner <th33xitus@gmail.com> #
|
||||||
|
# #
|
||||||
|
# This file is part of KIAUH - Klipper Installation And Update Helper #
|
||||||
|
# https://github.com/dw-0/kiauh #
|
||||||
|
# #
|
||||||
|
# This file may be distributed under the terms of the GNU GPLv3 license #
|
||||||
|
# ======================================================================= #
|
||||||
|
import shutil
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from components.klipper.klipper import Klipper
|
||||||
|
from components.moonraker.moonraker import Moonraker
|
||||||
|
from core.instance_manager.instance_manager import InstanceManager
|
||||||
|
from core.logger import DialogType, Logger
|
||||||
|
from core.services.backup_service import BackupService
|
||||||
|
from core.submodules.simple_config_parser.src.simple_config_parser.simple_config_parser import (
|
||||||
|
SimpleConfigParser,
|
||||||
|
)
|
||||||
|
from extensions.base_extension import BaseExtension
|
||||||
|
from extensions.tmc_autotune import (
|
||||||
|
KLIPPER_DIR,
|
||||||
|
KLIPPER_EXTENSIONS_PATH,
|
||||||
|
TMCA_DIR,
|
||||||
|
TMCA_EXAMPLE_CONFIG,
|
||||||
|
TMCA_MOONRAKER_UPDATER_NAME,
|
||||||
|
TMCA_REPO,
|
||||||
|
)
|
||||||
|
from utils.config_utils import add_config_section, remove_config_section
|
||||||
|
from utils.fs_utils import check_file_exist, create_symlink, run_remove_routines
|
||||||
|
from utils.git_utils import git_clone_wrapper, git_pull_wrapper
|
||||||
|
from utils.input_utils import get_confirm
|
||||||
|
from utils.instance_utils import get_instances
|
||||||
|
from utils.sys_utils import check_python_version
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyMethodMayBeStatic
|
||||||
|
class TmcAutotuneExtension(BaseExtension):
|
||||||
|
def install_extension(self, **kwargs) -> None:
|
||||||
|
Logger.print_status("Installing Klipper TMC Autotune...")
|
||||||
|
|
||||||
|
# Check for Python 3.x, aligned with upstream install script
|
||||||
|
if not check_python_version(3, 0):
|
||||||
|
Logger.print_warn("Python 3.x is required. Aborting install.")
|
||||||
|
return
|
||||||
|
|
||||||
|
klipper_dir_exists = check_file_exist(KLIPPER_DIR)
|
||||||
|
if not klipper_dir_exists:
|
||||||
|
Logger.print_warn(
|
||||||
|
"No Klipper directory found! Unable to install extension."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
tmca_exists = (
|
||||||
|
check_file_exist(TMCA_DIR)
|
||||||
|
and check_file_exist(KLIPPER_EXTENSIONS_PATH.joinpath("autotune_tmc.py"))
|
||||||
|
and check_file_exist(KLIPPER_EXTENSIONS_PATH.joinpath("motor_constants.py"))
|
||||||
|
and check_file_exist(KLIPPER_EXTENSIONS_PATH.joinpath("motor_database.cfg"))
|
||||||
|
)
|
||||||
|
|
||||||
|
overwrite = True
|
||||||
|
if tmca_exists:
|
||||||
|
overwrite = get_confirm(
|
||||||
|
question="Extension seems to be installed already. Overwrite?",
|
||||||
|
default_choice=True,
|
||||||
|
allow_go_back=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
if not overwrite:
|
||||||
|
Logger.print_warn("Installation aborted due to user request.")
|
||||||
|
return
|
||||||
|
|
||||||
|
add_moonraker_update_section = get_confirm(
|
||||||
|
question="Add Klipper TMC Autotune to Moonraker update manager(s)?",
|
||||||
|
default_choice=True,
|
||||||
|
allow_go_back=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
create_example_config = get_confirm(
|
||||||
|
question="Create an example autotune_tmc.cfg for each instance?",
|
||||||
|
default_choice=True,
|
||||||
|
allow_go_back=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
kl_instances = get_instances(Klipper)
|
||||||
|
|
||||||
|
if not self._stop_klipper_instances_interactively(
|
||||||
|
kl_instances, "installation of TMC Autotune"
|
||||||
|
):
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
git_clone_wrapper(TMCA_REPO, TMCA_DIR, force=True)
|
||||||
|
|
||||||
|
Logger.print_info("Creating symlinks in Klipper extras directory...")
|
||||||
|
create_symlink(
|
||||||
|
TMCA_DIR.joinpath("autotune_tmc.py"),
|
||||||
|
KLIPPER_EXTENSIONS_PATH.joinpath("autotune_tmc.py"),
|
||||||
|
)
|
||||||
|
create_symlink(
|
||||||
|
TMCA_DIR.joinpath("motor_constants.py"),
|
||||||
|
KLIPPER_EXTENSIONS_PATH.joinpath("motor_constants.py"),
|
||||||
|
)
|
||||||
|
create_symlink(
|
||||||
|
TMCA_DIR.joinpath("motor_database.cfg"),
|
||||||
|
KLIPPER_EXTENSIONS_PATH.joinpath("motor_database.cfg"),
|
||||||
|
)
|
||||||
|
Logger.print_ok(
|
||||||
|
"Symlinks created successfully for all instances.", end="\n\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
if create_example_config:
|
||||||
|
self._install_example_cfg(kl_instances)
|
||||||
|
else:
|
||||||
|
Logger.print_info(
|
||||||
|
"Skipping example config creation as per user request."
|
||||||
|
)
|
||||||
|
Logger.print_warn(
|
||||||
|
"Make sure to create and include an autotune_tmc.cfg in your printer.cfg in order to use the extension!"
|
||||||
|
)
|
||||||
|
|
||||||
|
if add_moonraker_update_section:
|
||||||
|
mr_instances = get_instances(Moonraker)
|
||||||
|
self._add_moonraker_update_manager_section(mr_instances)
|
||||||
|
else:
|
||||||
|
Logger.print_info(
|
||||||
|
"Skipping update section creation as per user request."
|
||||||
|
)
|
||||||
|
Logger.print_warn(
|
||||||
|
"Make sure to create the corresponding section in your moonraker.conf in order to have it appear in your frontend update manager!"
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
Logger.print_error(f"Error during Klipper TMC Autotune installation:\n{e}")
|
||||||
|
|
||||||
|
if kl_instances:
|
||||||
|
InstanceManager.start_all(kl_instances)
|
||||||
|
return
|
||||||
|
|
||||||
|
if kl_instances:
|
||||||
|
InstanceManager.start_all(kl_instances)
|
||||||
|
|
||||||
|
if create_example_config:
|
||||||
|
Logger.print_dialog(
|
||||||
|
DialogType.ATTENTION,
|
||||||
|
[
|
||||||
|
"Basic configuration files were created per instance. You must edit them to enable the extension.",
|
||||||
|
"Documentation:",
|
||||||
|
f"{TMCA_REPO}",
|
||||||
|
"\n\n",
|
||||||
|
"IMPORTANT:",
|
||||||
|
"Define [autotune_tmc] sections ONLY in 'autotune_tmc.cfg'. ",
|
||||||
|
"Do NOT add them to 'printer.cfg', contrary to official docs. "
|
||||||
|
"While not fatal, mixing configs breaks file segmentation and is bad practice.",
|
||||||
|
],
|
||||||
|
margin_bottom=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
Logger.print_ok("Klipper TMC Autotune installed successfully!")
|
||||||
|
|
||||||
|
def update_extension(self, **kwargs) -> None:
|
||||||
|
extension_installed = check_file_exist(TMCA_DIR)
|
||||||
|
if not extension_installed:
|
||||||
|
Logger.print_info("Extension does not seem to be installed! Skipping ...")
|
||||||
|
return
|
||||||
|
|
||||||
|
backup_before_update = get_confirm(
|
||||||
|
question="Backup Klipper TMC Autotune directory before update?",
|
||||||
|
default_choice=True,
|
||||||
|
allow_go_back=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
kl_instances = get_instances(Klipper)
|
||||||
|
|
||||||
|
if not self._stop_klipper_instances_interactively(
|
||||||
|
kl_instances, "update of TMC Autotune"
|
||||||
|
):
|
||||||
|
return
|
||||||
|
|
||||||
|
Logger.print_status("Updating Klipper TMC Autotune...")
|
||||||
|
try:
|
||||||
|
if backup_before_update:
|
||||||
|
Logger.print_status("Backing up Klipper TMC Autotune directory...")
|
||||||
|
svc = BackupService()
|
||||||
|
svc.backup_directory(
|
||||||
|
source_path=TMCA_DIR,
|
||||||
|
backup_name="klipper_tmc_autotune",
|
||||||
|
)
|
||||||
|
Logger.print_ok("Backup completed successfully.")
|
||||||
|
|
||||||
|
git_pull_wrapper(TMCA_DIR)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
Logger.print_error(f"Error during Klipper TMC Autotune update:\n{e}")
|
||||||
|
|
||||||
|
if kl_instances:
|
||||||
|
InstanceManager.start_all(kl_instances)
|
||||||
|
return
|
||||||
|
|
||||||
|
if kl_instances:
|
||||||
|
InstanceManager.start_all(kl_instances)
|
||||||
|
|
||||||
|
Logger.print_ok("Klipper TMC Autotune updated successfully.", end="\n\n")
|
||||||
|
|
||||||
|
def remove_extension(self, **kwargs) -> None:
|
||||||
|
extension_installed = check_file_exist(TMCA_DIR)
|
||||||
|
if not extension_installed:
|
||||||
|
Logger.print_info("Extension does not seem to be installed! Skipping ...")
|
||||||
|
return
|
||||||
|
|
||||||
|
kl_instances = get_instances(Klipper)
|
||||||
|
|
||||||
|
if not self._stop_klipper_instances_interactively(
|
||||||
|
kl_instances, "removal of TMC Autotune"
|
||||||
|
):
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
Logger.print_info("Removing Klipper TMC Autotune extension ...")
|
||||||
|
run_remove_routines(TMCA_DIR)
|
||||||
|
Logger.print_info("Removing symlinks from Klipper extras directory ...")
|
||||||
|
run_remove_routines(KLIPPER_EXTENSIONS_PATH.joinpath("autotune_tmc.py"))
|
||||||
|
run_remove_routines(KLIPPER_EXTENSIONS_PATH.joinpath("motor_constants.py"))
|
||||||
|
run_remove_routines(KLIPPER_EXTENSIONS_PATH.joinpath("motor_database.cfg"))
|
||||||
|
|
||||||
|
mr_instances: List[Moonraker] = get_instances(Moonraker)
|
||||||
|
self._remove_moonraker_update_manager_section(mr_instances)
|
||||||
|
|
||||||
|
Logger.print_info("Removing include from printer.cfg files ...")
|
||||||
|
BackupService().backup_printer_cfg()
|
||||||
|
remove_config_section("include autotune_tmc.cfg", kl_instances)
|
||||||
|
|
||||||
|
Logger.print_dialog(
|
||||||
|
DialogType.ATTENTION,
|
||||||
|
[
|
||||||
|
"Manual edits to 'printer.cfg' may be required if using exotic stepper configurations.",
|
||||||
|
"\n\n",
|
||||||
|
"NOTE:",
|
||||||
|
"'autotune_tmc.cfg' is NOT removed automatically. ",
|
||||||
|
"Please delete it manually if no longer needed.",
|
||||||
|
],
|
||||||
|
margin_bottom=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
Logger.print_error(f"Unable to remove extension:\n{e}")
|
||||||
|
|
||||||
|
if kl_instances:
|
||||||
|
InstanceManager.start_all(kl_instances)
|
||||||
|
return
|
||||||
|
|
||||||
|
if kl_instances:
|
||||||
|
InstanceManager.start_all(kl_instances)
|
||||||
|
|
||||||
|
Logger.print_ok("Klipper TMC Autotune removed successfully.")
|
||||||
|
|
||||||
|
def _install_example_cfg(self, kl_instances: List[Klipper]):
|
||||||
|
cfg_dirs = [instance.base.cfg_dir for instance in kl_instances]
|
||||||
|
|
||||||
|
for cfg_dir in cfg_dirs:
|
||||||
|
Logger.print_status(f"Create autotune_tmc.cfg in '{cfg_dir}' ...")
|
||||||
|
if check_file_exist(cfg_dir.joinpath("autotune_tmc.cfg")):
|
||||||
|
Logger.print_info("File already exists! Skipping ...")
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
shutil.copy(TMCA_EXAMPLE_CONFIG, cfg_dir.joinpath("autotune_tmc.cfg"))
|
||||||
|
Logger.print_ok("Done!")
|
||||||
|
except OSError as e:
|
||||||
|
Logger.print_error(f"Unable to create example config: {e}")
|
||||||
|
|
||||||
|
BackupService().backup_printer_cfg()
|
||||||
|
|
||||||
|
section = "include autotune_tmc.cfg"
|
||||||
|
cfg_files = [instance.cfg_file for instance in kl_instances]
|
||||||
|
for cfg_file in cfg_files:
|
||||||
|
Logger.print_status(f"Include autotune_tmc.cfg in '{cfg_file}' ...")
|
||||||
|
scp = SimpleConfigParser()
|
||||||
|
scp.read_file(cfg_file)
|
||||||
|
if scp.has_section(section):
|
||||||
|
Logger.print_info("Section already defined! Skipping ...")
|
||||||
|
continue
|
||||||
|
scp.add_section(section)
|
||||||
|
scp.write_file(cfg_file)
|
||||||
|
Logger.print_ok("Done!")
|
||||||
|
|
||||||
|
def _add_moonraker_update_manager_section(
|
||||||
|
self, mr_instances: List[Moonraker]
|
||||||
|
) -> None:
|
||||||
|
if not mr_instances:
|
||||||
|
Logger.print_dialog(
|
||||||
|
DialogType.WARNING,
|
||||||
|
[
|
||||||
|
"Moonraker not found! Klipper TMC Autotune update manager support "
|
||||||
|
"for Moonraker will not be added to moonraker.conf.",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
if not get_confirm(
|
||||||
|
"Continue Klipper TMC Autotune installation?",
|
||||||
|
default_choice=False,
|
||||||
|
allow_go_back=True,
|
||||||
|
):
|
||||||
|
Logger.print_info("Installation aborted due to user request.")
|
||||||
|
return
|
||||||
|
|
||||||
|
BackupService().backup_moonraker_conf()
|
||||||
|
|
||||||
|
add_config_section(
|
||||||
|
section=TMCA_MOONRAKER_UPDATER_NAME,
|
||||||
|
instances=mr_instances,
|
||||||
|
options=[
|
||||||
|
("type", "git_repo"),
|
||||||
|
("channel", "dev"),
|
||||||
|
("path", TMCA_DIR.as_posix()),
|
||||||
|
("origin", TMCA_REPO),
|
||||||
|
("managed_services", "klipper"),
|
||||||
|
("primary_branch", "main"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
InstanceManager.restart_all(mr_instances)
|
||||||
|
|
||||||
|
Logger.print_ok(
|
||||||
|
"Klipper TMC Autotune successfully added to Moonraker update manager(s)!"
|
||||||
|
)
|
||||||
|
|
||||||
|
def _remove_moonraker_update_manager_section(
|
||||||
|
self, mr_instances: List[Moonraker]
|
||||||
|
) -> None:
|
||||||
|
if not mr_instances:
|
||||||
|
Logger.print_dialog(
|
||||||
|
DialogType.WARNING,
|
||||||
|
[
|
||||||
|
"Moonraker not found! Klipper TMC Autotune update manager support "
|
||||||
|
"for Moonraker will not be removed from moonraker.conf.",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
BackupService().backup_moonraker_conf()
|
||||||
|
|
||||||
|
remove_config_section("update_manager klipper_tmc_autotune", mr_instances)
|
||||||
|
InstanceManager.restart_all(mr_instances)
|
||||||
|
|
||||||
|
Logger.print_ok(
|
||||||
|
"Klipper TMC Autotune successfully removed from Moonraker update manager(s)!"
|
||||||
|
)
|
||||||
|
|
||||||
|
def _stop_klipper_instances_interactively(
|
||||||
|
self, kl_instances: List[Klipper], operation_name: str = "operation"
|
||||||
|
) -> bool:
|
||||||
|
"""
|
||||||
|
Interactively stops all active Klipper instances, warning the user that ongoing prints will be disrupted.
|
||||||
|
|
||||||
|
:param kl_instances: List of Klipper instances to stop.
|
||||||
|
:param operation_name: Optional name of the operation being performed (for user messaging). Do NOT capitalize.
|
||||||
|
:return: True if instances were stopped or no instances found, False if operation was aborted.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not kl_instances:
|
||||||
|
Logger.print_warn("No instances found, skipping instance stopping.")
|
||||||
|
return True
|
||||||
|
|
||||||
|
Logger.print_dialog(
|
||||||
|
DialogType.ATTENTION,
|
||||||
|
[
|
||||||
|
"Do NOT continue if there are ongoing prints running",
|
||||||
|
f"All Klipper instances will be restarted during the {operation_name} and "
|
||||||
|
"ongoing prints WILL FAIL.",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
stop_klipper = get_confirm(
|
||||||
|
question=f"Stop Klipper now and proceed with {operation_name}?",
|
||||||
|
default_choice=False,
|
||||||
|
allow_go_back=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
if stop_klipper:
|
||||||
|
InstanceManager.stop_all(kl_instances)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
Logger.print_warn(
|
||||||
|
f"{operation_name.capitalize()} aborted due to user request."
|
||||||
|
)
|
||||||
|
return False
|
||||||
Reference in New Issue
Block a user