From f76f2651999347ae5461bb0e53c057554248dbf1 Mon Sep 17 00:00:00 2001 From: Andrey Kozhevnikov Date: Tue, 11 Mar 2025 02:42:59 +0700 Subject: [PATCH] feat(advanced): install input shaper dependencies Signed-off-by: Andrey Kozhevnikov --- kiauh/components/klipper/klipper_utils.py | 34 ++++++++++++++++++++++- kiauh/core/menus/advanced_menu.py | 19 +++++++++---- kiauh/utils/sys_utils.py | 32 +++++++++++++++++++++ 3 files changed, 78 insertions(+), 7 deletions(-) diff --git a/kiauh/components/klipper/klipper_utils.py b/kiauh/components/klipper/klipper_utils.py index 918d0f1..08f1fc4 100644 --- a/kiauh/components/klipper/klipper_utils.py +++ b/kiauh/components/klipper/klipper_utils.py @@ -43,7 +43,7 @@ from utils.common import check_install_dependencies, get_install_status from utils.fs_utils import check_file_exist from utils.input_utils import get_confirm, get_number_input, get_string_input from utils.instance_utils import get_instances -from utils.sys_utils import cmd_sysctl_service, parse_packages_from_file +from utils.sys_utils import cmd_sysctl_service, parse_packages_from_file, install_python_packages def get_klipper_status() -> ComponentStatus: @@ -211,3 +211,35 @@ def install_klipper_packages() -> None: packages.append("dbus") check_install_dependencies({*packages}) + + +def install_input_shaper_deps() -> None: + Logger.print_dialog( + DialogType.CUSTOM, + [ + "Resonance measurements and shaper auto-calibration require additional " + "software dependencies not installed by default. " + "If you agree, the following additional debian packages will be installed:", + "\n\n", + "python3-numpy python3-matplotlib libatlas-base-dev libopenblas-dev", + "\n\n", + "And also the following pip package will be installed: " + "\n\n", + "numpy", + ], + custom_title="Install Input Shaper Dependencies", + ) + if not get_confirm("Do you want to install required packages?", default_choice=False): + return + + apt_deps = ( + "python3-numpy", + "python3-matplotlib", + "libatlas-base-dev", + "libopenblas-dev", + ) + check_install_dependencies({*apt_deps}) + + py_deps = ("numpy",) + + install_python_packages(KLIPPER_ENV_DIR, {*py_deps}) diff --git a/kiauh/core/menus/advanced_menu.py b/kiauh/core/menus/advanced_menu.py index 543d7b4..33e9fa5 100644 --- a/kiauh/core/menus/advanced_menu.py +++ b/kiauh/core/menus/advanced_menu.py @@ -13,6 +13,7 @@ from typing import Type from components.klipper import KLIPPER_DIR from components.klipper.klipper import Klipper +from components.klipper.klipper_utils import install_input_shaper_deps from components.klipper_firmware.menus.klipper_build_menu import ( KlipperBuildFirmwareMenu, KlipperKConfigMenu, @@ -50,9 +51,10 @@ class AdvancedMenu(BaseMenu): "2": Option(method=self.flash), "3": Option(method=self.build_flash), "4": Option(method=self.get_id), - "5": Option(method=self.klipper_rollback), - "6": Option(method=self.moonraker_rollback), - "7": Option(method=self.change_hostname), + "5": Option(method=self.input_shaper), + "6": Option(method=self.klipper_rollback), + "7": Option(method=self.moonraker_rollback), + "8": Option(method=self.change_hostname), } def print_menu(self) -> None: @@ -60,11 +62,13 @@ class AdvancedMenu(BaseMenu): """ ╟───────────────────────────┬───────────────────────────╢ ║ Klipper Firmware: │ Repository Rollback: ║ - ║ 1) [Build] │ 5) [Klipper] ║ - ║ 2) [Flash] │ 6) [Moonraker] ║ + ║ 1) [Build] │ 6) [Klipper] ║ + ║ 2) [Flash] │ 7) [Moonraker] ║ ║ 3) [Build + Flash] │ ║ ║ 4) [Get MCU ID] │ System: ║ - ║ │ 7) [Change hostname] ║ + ║ │ 8) [Change hostname] ║ + ║ Extra dependencies: │ ║ + ║ 5) [Input shaper] │ ║ ╟───────────────────────────┴───────────────────────────╢ """ )[1:] @@ -97,3 +101,6 @@ class AdvancedMenu(BaseMenu): def change_hostname(self, **kwargs) -> None: change_system_hostname() + + def input_shaper(self, **kwargs) -> None: + install_input_shaper_deps() diff --git a/kiauh/utils/sys_utils.py b/kiauh/utils/sys_utils.py index 5a83933..f2bcf70 100644 --- a/kiauh/utils/sys_utils.py +++ b/kiauh/utils/sys_utils.py @@ -197,6 +197,38 @@ def install_python_requirements(target: Path, requirements: Path) -> None: raise VenvCreationFailedException(log) +def install_python_packages(target: Path, packages: List[str]) -> None: + """ + Installs the python packages based on a provided packages list | + :param target: Path of the virtualenv + :param packages: str list of required packages + :return: None + """ + try: + # always update pip before installing requirements + update_python_pip(target) + + Logger.print_status("Installing Python requirements ...") + command = [ + target.joinpath("bin/pip").as_posix(), + "install", + ] + for pkg in packages: + command.append(pkg) + result = run(command, stderr=PIPE, text=True) + + if result.returncode != 0 or result.stderr: + Logger.print_error(f"{result.stderr}", False) + raise VenvCreationFailedException("Installing Python requirements failed!") + + Logger.print_ok("Installing Python requirements successful!") + + except Exception as e: + log = f"Error installing Python requirements: {e}" + Logger.print_error(log) + raise VenvCreationFailedException(log) + + def update_system_package_lists(silent: bool, rls_info_change=False) -> None: """ Updates the systems package list |