diff --git a/.gitignore b/.gitignore index 6360850..6514945 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ +.vscode .old **.pyc \ No newline at end of file diff --git a/extended_macro/delayed_extended.py b/extended_macro/delayed_extended.py index f640591..30e77ef 100644 --- a/extended_macro/delayed_extended.py +++ b/extended_macro/delayed_extended.py @@ -8,7 +8,7 @@ # import logging -import delayed_gcode +from .delayed_gcode import DelayedGcode ###################################################################### # Extended Delayed GCode macro @@ -16,7 +16,7 @@ # # Inherits DelayedGcode from delayed_gcode.py # Only changes the template objects -class ExtendedDelayedGcode(delayed_gcode.DelayedGcode): +class ExtendedDelayedGcode(DelayedGcode): def __init__(self, config): self.printer = config.get_printer() self.reactor = self.printer.get_reactor() diff --git a/extended_macro/extended_macro.py b/extended_macro/extended_macro.py index 26e5e64..94578da 100644 --- a/extended_macro/extended_macro.py +++ b/extended_macro/extended_macro.py @@ -41,7 +41,7 @@ def __init__(self, printer, env, name, script): raise printer.config_error(msg) # Inherits PrinterGCodeMacro from gcode_macro.py -# Code added to utilize +# Code added to utilize class ExtendedPrinterGCodeMacro(PrinterGCodeMacro, object): #Dummy `object` required due to the Python 2 requirement for using super() def __init__(self, config): super(ExtendedPrinterGCodeMacro, self).__init__(config) diff --git a/extended_macro/extended_template.py b/extended_macro/extended_template.py index 59f1120..32933a5 100644 --- a/extended_macro/extended_template.py +++ b/extended_macro/extended_template.py @@ -6,11 +6,11 @@ import flatten_dict # DEFAULTS -# The default imports to be loaded by extended_template. +# The default imports to be loaded by extended_template. # These do not need to be defined by the user in their config file # If there is a name collision, the default imports will be given priority # while the user defined functions are renamed with an underscore. -# +# # For example, if the user were to define their own function named `list` (the same name as a default below), # the user defined `list` will be renamed to `_list`. DEFAULTS = { @@ -49,7 +49,7 @@ def __init__(self, yaml_path, config): with open(yaml_path, 'r') as f: self.yaml = yaml.load(f, Loader=yaml.Loader) - + func_yaml = self.yaml.get('functions',{}) filter_yaml = self.yaml.get('filters', {}) self._funcs = self._import_function_dict(func_yaml) @@ -58,7 +58,7 @@ def __init__(self, yaml_path, config): # Loops through each item in the config, passes # the data off to _import_function which will return # the actual function if it exists, and then adds - # each function to the function dictionary so they can + # each function to the function dictionary so they can # be added by extended_macro to the Jinja environment def GetFunctions(self): @@ -112,7 +112,7 @@ def get_macro(self, macro_name): macro = self.printer.lookup_object('extended_macro %s' % (macro_name)) except: macro = self.printer.lookup_object('gcode_macro %s' % (macro_name)) - + else: macro = self.printer.lookup_object(macro_name) @@ -120,11 +120,11 @@ def get_macro(self, macro_name): # update_gcode_variable # - # Set the value of any GCode Variable for another (or the current) macro. + # Set the value of any GCode Variable for another (or the current) macro. # # Main differences between SET_GCODE_VARIABLE: # * Can only be called in a macro - # * Can update any variable, not just literals. + # * Can update any variable, not just literals. # * Does not require running through the interpreter; instead is only run inside Python # def update_gcode_variable(self, macro_name, variable, value): @@ -144,7 +144,7 @@ def call_macro(self, macro_name, **params): kwparams['params'] = params macro.template.run_gcode_from_command(kwparams) - # update_dict + # update_dict # # Allows for updating a nested dictionary by passing a list, set, or tuple of keys. # If the set of keys do not lead to a valid existing item, the keys will be created. @@ -177,7 +177,7 @@ def __init__(self, config): self.printer = self.config.get_printer() self.gcode = self.printer.lookup_object('gcode') self.Log = Logger(config) - + self.config_path = config.get('path', None) self.Loader = self._get_loader() self.Functions = self._import_functions() @@ -203,14 +203,14 @@ def _import_functions(self): else: u_key = key all_funcs[u_key] = val - + return all_funcs def _get_loader(self, ext=None): loader = None if ext is None: ext = self.config_path.split('.')[-1] - + for l in LOADERS: c_ext = l['extensions'] @@ -233,7 +233,7 @@ def _load_defaults(self): loader = self._get_loader('default') funcs = self._load_functions(loader) return funcs - + def _load_filters(self): return self.Loader.GetFilters() @@ -246,7 +246,7 @@ def _load_functions(self, loader=None): return funcs, defaults_loaded def _insert_function(self, func_name, func): - if func_name in self.Functions: + if func_name in self.Functions: func_name = '_%s' % func_name def load_config(config): @@ -254,35 +254,35 @@ def load_config(config): # LOADERS # The definitions in this list will be used to determine the proper loader for the extensions given -# -# Since different loaders might need or want different methods of parsing the file, +# +# Since different loaders might need or want different methods of parsing the file, # the script expects that the loader is a function, not a class. The function should # process the config file and return a dictionary with the jinja function name as the key # and the actual Python function as the value -# +# # The loader for DEFAULTS should be defined with an extension of ['default'] # This loader will be ignored if the property loader.DefaultsLoaded property is true (see below) -# +# # Definition: {'extensions': , 'loader': } -# -# Arguments received: +# +# Arguments received: # * config_path: Path to config set in [extended_template] # * config: Config object received from Klipper # # Required Properties and Functions: # * loader.DefaultsLoaded : -# - If True, it is assumed the loader has loaded the defaults listed below. +# - If True, it is assumed the loader has loaded the defaults listed below. # - If False, assumes the loader has not loaded the defaults listed below. # - It is suggested that the Loader should never process defaults unless: # * The user defines the defaults in the config file # * The loader defines it's own defaults # * Any other scenario where it's better to load the defaults by the loader instead of separately -# * loader.GetFunctions(self) = +# * loader.GetFunctions(self) = # - Loads user-defined functions. -# * Optionally, +# * Optionally, # - Returns schema: {defined_function_name_for_jinja : function } -# -# +# +# LOADERS = [ { 'extensions': ['yaml','yml'], diff --git a/extended_macro/readme.md b/extended_macro/readme.md index f32cdde..f3e904d 100644 --- a/extended_macro/readme.md +++ b/extended_macro/readme.md @@ -1,4 +1,4 @@ -# extended_macro +# Extended_Template --- * Allow the use of custom Python functions in your Klipper macros by defining the functions in a YAML config file * By default includes many additional modules and functions. See below for more information. @@ -9,27 +9,24 @@ **Do not blindly download Python scripts, both for use in your macros and this script itself.** Read the script and ensure you understand what is going on. The scripts can be powerful and useful, but they can also be dangerous. If the script looks questionable, dangerous, or too confusing, it's better to assume that it is malicious. -**Installation:** -1. Write down the location of the following directories: +**What will happen when you run the Installation script:** +1. The script will determine if the following directories exist: * Klipper Extras: Usually located at `/home/USER/klipper/klippy/extras`. * Klippy Virtual Environment `bin` directory: Usually located at `/home/USER/klippy/bin` -2. Clone this repository or download `extended_macro.py`, `extended_template.py`, and `requirements.txt` -3. Move `extended_macro.py` and `extended_template.py` to your Klipper Extras folder. -4. Move `requirements.txt` to your home directory. -5. Run the following command, substituting `${KLIPPY_ENV}` with the Klippy Virtual Environment bin directory: - -``` -${KLIPPY_ENV}/pip install -r ${HOME}/requirements.txt -``` +2. It will clone this repository; the following files will be downloaded: + `extended_macro.py`, `extended_template.py`, and `delayed_extended.py` +3. The script will install additional software if this extension has not been installed before +4. The script creates a symbolic link from the clone Repo to the Klipper Extras folder for the following files: + `extended_macro.py`, `extended_template.py` and `delayed_extended.py` +5. If Klipper needs to be restarted the script will cause a Klipper restart. --- **Setup:** 1. In your Klipper config, add the following section. Nothing more is needed if you do not plan on using your own Python scripts: -``` +```INI [extended_template] ``` - --- **Adding your own Python functions** @@ -42,14 +39,16 @@ ${KLIPPY_ENV}/pip install -r ${HOME}/requirements.txt --- **Usage:** -See the examples folder for more guidance. +See the examples' folder for more guidance. + +When defining the macro, use `extended_macro` as the config name instead of `gcode_macro`. To use your function, you will wrap the name with curly brackets (`{gcode_function_name_goes_here}`). -When defining the macro, use `extended_macro` as the config name instead of `gcode_macro`. To use your function, you will wrap the name with curly brackets (`{gcode_function_name_goes_here}`). +When you need the macro to be used on an timer instead of `extended_macro` use `delayed_extended` as the section definition. --- **Defaults** -`extended_macro` comes with many default functions which do not need to be added or declared by the user. +`extended_macro` and `delayed_extended` comes with many default functions which do not need to be added or declared by the user. --- @@ -60,46 +59,43 @@ On your Run the following commands in the command prompt of the Raspberry Pi run ```BASH cd ~ -git clone https://github.com/droans/klipper_extras.git +git clone -b shell-install --single-branch git@github.com:droans/klipper_extras.git ``` -Next, install Extended Macro using our install script. As with any script, please take time and read the script first so you can ensure the safety. Alternatively, if you understand how, you may download the files and manually install Extended Macro: +Next, install Extended Template using our installation script. As with any script, please take time and read the script first, so you can ensure the safety. Alternatively, if you understand how, you may download the files and manually install Extended Macro: ```BASH ./klipper_extras/install.sh ``` -When the script finishes, copy the install script to your home directory so that we can edit it. On Line #3, you will need to adjust `FLAG=1` to `FLAG=0`. The reason for copying the file to your home directory is Moonraker will not like it if you edit the file while it is in the clone repo directory and will force you to overwrite the changes. - -```BASH -cp ${HOME}/klipper_extras/install.sh ${HOME}/extended_macro_install.sh -nano /home/pi/extended_macro_install.sh -``` - At this point, Extended Macro is ready to be used. If you wish to add this to your update manager, edit your `moonraker.conf` file and add the following: -```BASH -[update_manager extended_macro] +```INI +[update_manager extended_template] type: git_repo -primary_branch: main +primary_branch: shell-install path: ~/klipper_extras origin: https://github.com/droans/klipper_extras.git env: ~/klippy-env/bin/python requirements: extended_macro/requirements.txt -install_script: ./../extended_macro_install.sh +install_script: install.sh is_system_service: False managed_services: klipper ``` -With this above setup pointing the installation script to your home directory, anytime the extended_macro extension gets updated, your extended_macro_install.sh file will not be overwritten by the GitHub clone of the repo. +The script will automatically generate the `requirements.txt` file and (if the use chooses to have moonraker update this extension automatically) `extended_template_update.conf` file. -We want the `FLAG=0` to stay that way. You only need to install the additional software packages one time. Moonraker will take care of ensuring that the packages needed by the extension are updated (the `requirements` option takes care of that for you). +If the user chooses to have moonraker update this extension automatically, then the script will append the following to the end of your `moonraker.conf` file: +```INI +#add extended_template extension to Klipper +[include extended_template_update.conf] +``` --- *Custom Utility Functions*: -`update_gcode_variable(macro_name: str, variable: str, value: Any)`: Update a G-Code variable for any macro. Unlike `SET_GCODE_VARIABLE`, allows for non-literals to be passed and updated. +`update_gcode_variable(macro_name: str, variable: str, value: Any)`: Update a G-Code variable for any macro. Unlike `SET_GCODE_VARIABLE`, allows for non-literals to be passed and updated. `update_dict(dict: dict, keys: Union[list, tuple, set, str], value: Any)`: Update the value of a dictionary. Allows for a nested value to be updated if a list, tuple, or set is passed for `keys`. diff --git a/extended_macro/requirements.txt b/extended_macro/requirements.txt deleted file mode 100644 index b24e9a7..0000000 --- a/extended_macro/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -pyyaml==3.13 -numpy==1.16.6 -pandas==0.23.4 -flatten-dict==0.4.2 \ No newline at end of file diff --git a/install.sh b/install.sh old mode 100644 new mode 100755 index 311a646..a0097df --- a/install.sh +++ b/install.sh @@ -1,7 +1,5 @@ #!/bin/bash -FLAG=1 - # Force script to exit if an error occurs set -e @@ -14,16 +12,41 @@ SRCDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/ && pwd )" HOME_DIR="${HOME}" ENV_DIR="${HOME_DIR}/klippy-env/bin" EXTRAS_DIR="${HOME_DIR}/klipper/klippy/extras" +OLD_PRINTER_CONFIG_DIR="${HOME_DIR}/klipper_config" +PRINTER_CONFIG_DIR="${HOME_DIR}/printer_data/config" KLIPPY_PIP="${ENV_DIR}/pip" KLIPPY_PY="${ENV_DIR}/python" +KLIPPY_PY3="${ENV_DIR}/python3" + +PROMPTED_INPUT="Yes" function produce_newline() { echo " " } -# Step 1: Verify directories exist and pip and python are installed in ENV_DIR +# Step 1: Ensure script is not running as superuser +function verify_ready() { + if [ "$(id -u)" -eq 0 ]; then + echo "This script must not run as root" >&2 + echo "exiting the script..." >&2 + exit -1 + fi + check_klipper +} + +function check_klipper() { + if [ "$(sudo systemctl list-units --full -all -t service --no-legend | grep -F "klipper.service")" ]; then + echo "Klipper service found!" + else + echo "Klipper service not found, please install Klipper first" >&2 + echo "exiting the script..." >&2 + exit -1 + fi + return +} +# Step 2: Verify Klipper's virtual environment directory function validate_env_dir() { if [ -d "$ENV_DIR" ]; then if [ -L "$ENV_DIR" ]; then @@ -36,6 +59,7 @@ function validate_env_dir() { echo "ENV_DIR BASH variable being set to "$ENV_DIR"...." >&2 KLIPPY_PIP="${ENV_DIR}/pip" KLIPPY_PY="${ENV_DIR}/python" + KLIPPY_PY3="${ENV_DIR}/python3" return fi else @@ -45,6 +69,24 @@ function validate_env_dir() { return } +function change_env_dir() { + while [ true ] + do + read -p "New Klippy Python Environ Dir [${ENV_DIR}]: " PROMPTED_ENV_DIR + if [ -z "$PROMPTED_ENV_DIR" ]; then + PROMPTED_ENV_DIR=$ENV_DIR + break + else + break + fi + done + ENV_DIR=$PROMPTED_ENV_DIR + validate_env_dir + produce_newline + return +} + +# Step 3: Verify Klipper's EXTRAS directory function validate_extras_dir() { if [ -d "$EXTRAS_DIR" ]; then if [ -L "$EXTRAS_DIR" ]; then @@ -64,138 +106,320 @@ function validate_extras_dir() { return } -function change_env_dir() { +function change_extras_dir() { while [ true ] do - read -p "New Klippy Python Environ Dir [${ENV_DIR}]: " PROMPTED_ENV_DIR - if [ -z "$PROMPTED_ENV_DIR" ]; then - continue + read -p "New Klipper Extras Dir [${EXTRAS_DIR}]: " PROMPTED_EXTRAS_DIR + if [ -z "$PROMPTED_EXTRAS_DIR" ]; then + PROMPTED_EXTRAS_DIR=$EXTRAS_DIR + break else break fi done - ENV_DIR=$PROMPTED_ENV_DIR - validate_env_dir + EXTRAS_DIR=$PROMPTED_EXTRAS_DIR + validate_extras_dir produce_newline return } -function change_extras_dir() { +# Step 4: Verify Klipper's PRINTER CONFIG directory +function validate_printer_config_dir() { + if [ -d "$PRINTER_CONFIG_DIR" ]; then + if [ -L "$PRINTER_CONFIG_DIR" ]; then + # It is a symbolic links # + echo "Klipper Printer Config is a symbolic link found so this is not a real directory, try again ..." >&2 + PRINTER_CONFIG_DIR=$OLD_PRINTER_CONFIG_DIR + change_printer_config_dir + else + # It is a directory # + echo "Klipper Printer Config Directory exists ..." + echo "PRINTER_CONFIG_DIR BASH variable being set to "$PRINTER_CONFIG_DIR"...." >&2 + return + fi + else + echo "Klipper Printer Config Dirctory does not exists!..." >&2 + PRINTER_CONFIG_DIR=$OLD_PRINTER_CONFIG_DIR + change_printer_config_dir + fi + return +} + +function change_printer_config_dir() { while [ true ] do - read -p "New Klipper Extras Dir [${EXTRAS_DIR}]: " PROMPTED_EXTRAS_DIR - if [ -z "$PROMPTED_EXTRAS_DIR" ]; then - continue + read -p "New Printer Config Dir [${PRINTER_CONFIG_DIR}]: " PROMPTED_PRINTER_CONFIG_DIR + if [ -z "$PROMPTED_PRINTER_CONFIG_DIR" ]; then + PROMPTED_PRINTER_CONFIG_DIR=$PRINTER_CONFIG_DIR + break else break fi done - EXTRAS_DIR=$PROMPTED_EXTRAS_DIR - validate_extras_dir + PRINTER_CONFIG_DIR=$PROMPTED_PRINTER_CONFIG_DIR + validate_printer_config_dir produce_newline return } -function validate_pip_installed() { - if ! [ -x "$(command -v ${KLIPPY_PIP})" ]; then - echo 'Error: pip is not installed.' >&2 - change_pip - if ! [ -x "$(command -v ${KLIPPY_PIP})" ]; then - echo 'Error: pip is still not installed.' >&2 - echo 'Exiting the script, please install pip into the Klipper Environment, manually!' >&2 - echo "exiting the script..." >&2 - exit -1 - fi +# Step 5: Deteremine Klipper's virtual enviroment python version +function check_env_version() { + export PYTHON_VERSION=`$KLIPPY_PY -c 'import sys; print(".".join(map(str, sys.version_info[:1])))'` + if [ $? -eq 0 ]; then + echo "Found Python version for virtual environment; Python version="$PYTHON_VERSION fi - echo "pip is found to be installed into the Klipper Environment!" } -function validate_python_installed() { - if ! [ -x "$(command -v ${KLIPPY_PY})" ]; then - echo 'Error: python is not installed.' >&2 - change_py - if ! [ -x "$(command -v ${KLIPPY_PY})" ]; then - echo 'Error: python is still not installed.' >&2 - echo 'Exiting the script, please install python into the Klipper Environment, manually!' >&2 - echo "exiting the script..." >&2 - exit -1 - fi +# Step 6: Verify PIP is installed in Klipper's virtual environment +function validate_pip_installed() { + if ! [ -x "$(command -v ${KLIPPY_PIP})" ]; then + echo 'Error: pip is not installed.' >&2 + change_pip + if ! [ -x "$(command -v ${KLIPPY_PIP})" ]; then + echo 'Error: pip is still not installed.' >&2 + echo 'Exiting the script, please install pip into the Klipper Environment, manually!' >&2 + echo "exiting the script..." >&2 + exit -1 + fi fi - echo "python is found to be installed into the Klipper Environment!" + echo "pip is found to be installed into the Klipper Environment!" } function change_pip() { - while [[ $string != 'string' ]] || [[ $string == '' ]] + while [ true ] do - read -p "New Klippy Environment Pip Location [${KLIPPY_PIP}]: " string - echo "Enter a valid string" >&2 + read -p "New Klippy Environment Pip Location [${KLIPPY_PIP}]: " PROMPTED_KLIPPY_PIP + if [ -z "$PROMPTED_KLIPPY_PIP" ]; then + PROMPTED_KLIPPY_PIP="${KLIPPY_PIP//pip}" + break + else + break + fi done - PROMPTED_KLIPPY_PIP=$string KLIPPY_PIP=$PROMPTED_KLIPPY_PIP'/pip' echo "KLIPPY_PIP BASH variable being set to "$KLIPPY_PIP"...." >&2 produce_newline return } +# Step 7: Verify the appropriate version of python is installed in Klipper's virtual environment +function validate_python_installed() { + if [[ $PYTHON_VERSION == 2 ]]; then + if ! [ -x "$(command -v ${KLIPPY_PY})" ]; then + echo 'Error: python is not installed.' >&2 + change_py + if ! [ -x "$(command -v ${KLIPPY_PY})" ]; then + echo 'Error: python is still not installed.' >&2 + echo 'Exiting the script, please install python into the Klipper Environment, manually!' >&2 + echo "exiting the script..." >&2 + exit -1 + fi + fi + echo "python is found to be installed into the Klipper Environment!" + elif [[ $PYTHON_VERSION == 3 ]]; then + validate_python3_installed + fi +} + function change_py() { - while [[ $string != 'string' ]] || [[ $string == '' ]] + while [ true ] do - read -p "New Klippy Environment Python Location [${KLIPPY_PY}]: " string - echo "Enter a valid string" >&2 + read -p "New Klippy Environment Python Location [${KLIPPY_PY}]: " PROMPTED_KLIPPY_PY + if [ -z "$PROMPTED_KLIPPY_PY" ]; then + PROMPTED_KLIPPY_PY="${KLIPPY_PY//python}" + break + else + break + fi done - PROMPTED_KLIPPY_PY=$string KLIPPY_PY=$PROMPTED_KLIPPY_PY'/python' echo "KLIPPY_PY BASH variable being set to "$KLIPPY_PY"...." >&2 produce_newline return } -# Step 2: install requirement.txt -function install_requirements() { - if [[ "$FLAG" == 1 ]]; then - echo "INSTALLING ADDITIONAL SOFTWARE PACKAGES...." - echo "NOTE: if this is the first time installing these packages, please be patient, It could take up to 10 minutes" - #SRCDIR=/home/pi/klipper_extras - cp ${SRCDIR}'/extended_macro/requirements.txt' ${HOME}'/requirements.txt' - if [ $? -eq 0 ]; then - echo "copied requirements.txt to "${HOME}" sucessfully." - echo "Attempting the pip install of requirements.txt file......" - $KLIPPY_PIP install -r $HOME/requirements.txt - if [ $? -eq 0 ]; then - produce_newline - echo "All required Software packages have been sucessfully installed!" - else - echo "An error occurred when installing the required Software Packages!">&2 - echo "Please run the following command, manually:" >&2 - echo "run this command:" '"'$KLIPPY_PIP' install -r' ${HOME}'/requirements.txt' '"' >&2 - echo "exiting the script..." >&2 - exit -1 - fi - else - echo "The copy of requirements.txt to "${HOME}" did not work, exiting the script" >&2 +function validate_python3_installed() { + if ! [ -x "$(command -v ${KLIPPY_PY3})" ]; then + echo 'Error: python3 is not installed.' >&2 + change_py3 + if ! [ -x "$(command -v ${KLIPPY_PY3})" ]; then + echo 'Error: python3 is still not installed.' >&2 + echo 'Exiting the script, please install python3 into the Klipper Environment, manually!' >&2 + echo "exiting the script..." >&2 exit -1 fi fi - echo "Reminder: Edit the script file and set FLAG=0 at the top of the script file" >&2 - echo "Installing Additional Software Packages only needs to be done ONE time" >&2 - if [[ "$FLAG" == 0 ]]; then - echo "If the FLAG=0 setting is due to the fact that the additional software has already been installed,">&2 - echo "please ignore the above three messages.">&2 + echo "python3 is found to be installed into the Klipper Environment!" + return +} + +function change_py3() { + while [ true ] + do + read -p "New Klippy Environment Python3 Location [${KLIPPY_PY3}]: " PROMPTED_KLIPPY_PY3 + if [ -z "$PROMPTED_KLIPPY_PY3" ]; then + PROMPTED_KLIPPY_PY3="${KLIPPY_PY3//python3}" + break + else + break + fi + done + KLIPPY_PY3=$PROMPTED_KLIPPY_PY3'/python3' + echo "KLIPPY_PY3 BASH variable being set to "$KLIPPY_PY3"...." >&2 + produce_newline + return +} + +# Step 8: Check if the extensions are already present. +# This is a way to check if this is the initial installation. +function check_existing() { + local -i existing=0 + for extension in ${EXTENSION_LIST}; do + [ -e "${KLIPPER_PATH}/klippy/extras/${extension}" ] && existing=1 || existing=0 + [ ${existing} -eq 0 ] && break + done + echo ${existing} +} + +# Step 9: optionaly install requirement.txt +function install_requirements() { + echo "CREATING requirements.txt file for the python"$PYTHON_VERSION" Klipper virtual environment....." + create_requirements_file + echo "INSTALLING ADDITIONAL SOFTWARE PACKAGES...." + echo "NOTE: if this is the first time installing these packages, please be patient, It could take up to 10 minutes" + #SRCDIR=/home/pi/klipper_extras + echo "Attempting the python install of requirements.txt file......" + $KLIPPY_PIP install -r $SRCDIR/extended_macro/requirements.txt + if [ $? -eq 0 ]; then + produce_newline + echo "All required Software packages have been sucessfully installed!" + prompt_user_update + else + echo "An error occurred when installing the required Software Packages!" >&2 + echo "Please run the following command, manually:" >&2 + echo "run this command:" '"'$KLIPPY_PIP' install -r' $SRCDIR'/extended_macro/requirements.txt' '"' >&2 + echo "exiting the script..." >&2 + exit -1 fi } -# Step 3: Verify Klipper has been installed -function check_klipper() { - if [ "$(sudo systemctl list-units --full -all -t service --no-legend | grep -F "klipper.service")" ]; then - echo "Klipper service found!" +function create_requirements_file() { + if [[ $PYTHON_VERSION == 2 ]]; then + touch ${SRCDIR}/extended_macro/requirements.txt + echo "pyyaml==3.13" >> ${SRCDIR}/extended_macro/requirements.txt + echo "numpy==1.16.6" >> ${SRCDIR}/extended_macro/requirements.txt + echo "flatten-dict==0.4.2" >> ${SRCDIR}/extended_macro/requirements.txt + echo "pandas==0.23.4" >> ${SRCDIR}/extended_macro/requirements.txt + elif [[ $PYTHON_VERSION == 3 ]]; then + touch ${SRCDIR}/extended_macro/requirements.txt + echo "pyyaml==5.3.1" >> ${SRCDIR}/extended_macro/requirements.txt + echo "numpy==1.24.1" >> ${SRCDIR}/extended_macro/requirements.txt + echo "flatten-dict==0.4.2" >> ${SRCDIR}/extended_macro/requirements.txt + echo "pandas==1.5.3" >> ${SRCDIR}/extended_macro/requirements.txt else - echo "Klipper service not found, please install Klipper first" >&2 + echo "The Python Version of '"$PYTHON_VERSION"' does not exists for the Klipper firmware, exiting the script" >&2 + exit -1 + fi + return +} + +function prompt_user_update() { + produce_newline + while [ true ] + do + read -p "Do you plan on using moonraker's update manager to automatically update this extension: [${PROMPTED_INPUT}]: " PROMPT_INPUT + if [ -z "$PROMPT_INPUT" ]; then + PROMPT_INPUT=$PROMPTED_INPUT + break + else + break + fi + done + PROMPTED_INPUT=$PROMPT_INPUT + echo "PROMPTED_INPUT BASH variable being set to "$PROMPTED_INPUT"...." >&2 + validate_user_response + return +} + +function validate_user_response() { + while true; do + case $PROMPTED_INPUT in + yes ) echo ok, we will proceed; + copy_moonraker_update_file; + break;; + Yes ) echo ok, we will proceed; + copy_moonraker_update_file; + break;; + y ) echo ok, we will proceed; + copy_moonraker_update_file; + break;; + Y ) echo ok, we will proceed; + copy_moonraker_update_file; + break;; + no ) echo ok, we will not proceed; + break;; + No ) echo ok, we will not proceed; + break;; + n ) echo ok, we will not proceed; + break;; + N ) echo ok, we will not proceed; + break;; + * ) echo invalid response;; + esac + done + return +} + +function copy_moonraker_update_file() { + produce_newline + produce_newline + echo "CREATING extended_template_update.conf file for Moonraker's [update manager]....." + create_moonraker_file + echo "Trying to add include statement to the end of moonraker.conf file" + echo " " >> ${PRINTER_CONFIG_DIR}/moonraker.conf + echo "#add extended_template extension to Klipper " >> ${PRINTER_CONFIG_DIR}/moonraker.conf + echo "[include extended_template_update.conf]" >> ${PRINTER_CONFIG_DIR}/moonraker.conf + if [ $? -eq 0 ]; then + echo "Sucessfully appended [include extended_template_update.conf] to the end of "${PRINTER_CONFIG_DIR}"/moonraker.conf file!" + else + echo "An error occurred when trying to append [include extended_template_update.conf] to the "${PRINTER_CONFIG_DIR}"/moonraker.conf file!" >&2 + echo "Please run the following command, manually:" >&2 + echo "run this command:" '"'`echo `"[include extended_template_update.conf]"` >> moonraker.conf`'"' >&2 echo "exiting the script..." >&2 exit -1 fi + # copy the include file over to ${PRINTER_CONFIG_DIR} + #SRCDIR=/home/pi/klipper_extras + echo "Trying...cp "${SRCDIR}"/extended_macro/extended_template_update.conf "${PRINTER_CONFIG_DIR}"/extended_template_update.conf" + cp ${SRCDIR}'/extended_macro/extended_template_update.conf' ${PRINTER_CONFIG_DIR}'/extended_template_update.conf' + if [ $? -eq 0 ]; then + echo "Sucessfully copied extended_template_update.conf to "${PRINTER_CONFIG_DIR}"!" + else + echo "An error occurred when trying to copy extended_template_update.conf to "${PRINTER_CONFIG_DIR}"!">&2 + echo "Please run the following command, manually:" >&2 + echo "run this command:" '"'`cp `${SRCDIR}'/extended_macro/extended_template_update.conf' ${PRINTER_CONFIG_DIR}'/extended_template_update.conf''"' >&2 + echo "exiting the script..." >&2 + exit -1 + fi + return } -# Step 4: Link extension to Klipper +function create_moonraker_file() { + touch ${SRCDIR}/extended_macro/extended_template_update.conf + echo "[update_manager extended_template]" >> ${SRCDIR}/extended_macro/extended_template_update.conf + echo "type: git_repo" >> ${SRCDIR}/extended_macro/extended_template_update.conf + echo "primary_branch: main" >> ${SRCDIR}/extended_macro/extended_template_update.conf + echo "path: ~/klipper_extras" >> ${SRCDIR}/extended_macro/extended_template_update.conf + echo "origin: https://github.com/droans/klipper_extras.git" >> ${SRCDIR}/extended_macro/extended_template_update.conf + echo "env: ~/klippy-env/bin/python" >> ${SRCDIR}/extended_macro/extended_template_update.conf + echo "requirements: extended_macro/requirements.txt" >> ${SRCDIR}/extended_macro/extended_template_update.conf + echo "install_script: install.sh" >> ${SRCDIR}/extended_macro/extended_template_update.conf + echo "is_system_service: False" >> ${SRCDIR}/extended_macro/extended_template_update.conf + echo "managed_services: klipper" >> ${SRCDIR}/extended_macro/extended_template_update.conf + return +} + +# Step 10: Link extension to Klipper function link_extension() { echo "Linking extensions to Klipper..." for extension in ${EXTENSION_LIST}; do @@ -203,33 +427,32 @@ function link_extension() { done } -# Step 5: restarting Klipper +# Step 11: optionally restarting Klipper function restart_klipper() { echo "Restarting Klipper..." sudo systemctl restart klipper } -function verify_ready() { - if [ "$(id -u)" -eq 0 ]; then - echo "This script must not run as root" >&2 - echo "exiting the script..." >&2 - exit -1 - fi - check_klipper -} - while getopts "k:" arg; do case ${arg} in k) KLIPPER_PATH=${OPTARG} ;; esac done + +verify_ready validate_env_dir validate_extras_dir +validate_printer_config_dir +check_env_version validate_pip_installed validate_python_installed -install_requirements -verify_ready +existing_install=$(check_existing) +if [ ${existing_install} -eq 0 ]; then + install_requirements +fi link_extension -restart_klipper +if [ ${existing_install} -eq 0 ]; then + restart_klipper +fi