From d91d01ae2c6c42d468d8fcedf3bb24968e46196d Mon Sep 17 00:00:00 2001 From: th33xitus Date: Wed, 28 Oct 2020 20:39:34 +0100 Subject: [PATCH 1/8] fix: rework klipper webui installers --- .../{mainsail_macros.cfg => webui_macros.cfg} | 12 +- scripts/install_fluidd.sh | 94 ------- scripts/install_klipper_webui.sh | 246 ++++++++++++++++++ scripts/install_mainsail.sh | 103 -------- scripts/install_moonraker.sh | 146 ++++------- scripts/ui/install_menu.sh | 4 +- 6 files changed, 295 insertions(+), 310 deletions(-) rename resources/{mainsail_macros.cfg => webui_macros.cfg} (74%) delete mode 100755 scripts/install_fluidd.sh create mode 100755 scripts/install_klipper_webui.sh delete mode 100755 scripts/install_mainsail.sh diff --git a/resources/mainsail_macros.cfg b/resources/webui_macros.cfg similarity index 74% rename from resources/mainsail_macros.cfg rename to resources/webui_macros.cfg index f89deda..5becc06 100644 --- a/resources/mainsail_macros.cfg +++ b/resources/webui_macros.cfg @@ -1,6 +1,4 @@ -########################## -### CREATED WITH KIAUH ### -########################## +### AUTOCREATED WITH KIAUH ### #is required to load the pause_resume module in klipper [pause_resume] @@ -31,14 +29,8 @@ gcode: [gcode_macro CANCEL_PRINT] rename_existing: BASE_CANCEL_PRINT -default_parameter_X: 230 #edit to your park position -default_parameter_Y: 230 #edit to your park position -default_parameter_Z: 10 #edit to your park position gcode: - M104 S0 - M140 S0 - M141 S0 - M106 S0 + TURN_OFF_HEATERS CLEAR_PAUSE SDCARD_RESET_FILE BASE_CANCEL_PRINT diff --git a/scripts/install_fluidd.sh b/scripts/install_fluidd.sh deleted file mode 100755 index 4af74fb..0000000 --- a/scripts/install_fluidd.sh +++ /dev/null @@ -1,94 +0,0 @@ -install_fluidd(){ - if [ "$INST_FLUIDD" = "true" ]; then - #check if moonraker is already installed - check_moonraker - if [ "$MOONRAKER_SERVICE_FOUND" = "true" ]; then - #check for other enabled web interfaces - unset SET_LISTEN_PORT - detect_enabled_sites - #check if another site already listens to port 80 - fluidd_port_check - #creating the fluidd nginx cfg - set_nginx_cfg "fluidd" - test_nginx "$SET_LISTEN_PORT" - fluidd_setup - fi - fi -} - -fluidd_port_check(){ - if [ "$FLUIDD_ENABLED" = "false" ]; then - if [ "$SITE_ENABLED" = "true" ]; then - status_msg "Detected other enabled interfaces:" - [ "$OCTOPRINT_ENABLED" = "true" ] && echo " ${cyan}● OctoPrint - Port: $OCTOPRINT_PORT${default}" - [ "$MAINSAIL_ENABLED" = "true" ] && echo " ${cyan}● Mainsail - Port: $MAINSAIL_PORT${default}" - [ "$DWC2_ENABLED" = "true" ] && echo " ${cyan}● DWC2 - Port: $DWC2_PORT${default}" - if [ "$MAINSAIL_PORT" = "80" ] || [ "$DWC2_PORT" = "80" ] || [ "$OCTOPRINT_PORT" = "80" ]; then - PORT_80_BLOCKED="true" - select_fluidd_port - fi - else - DEFAULT_PORT=$(grep listen ${SRCDIR}/kiauh/resources/fluidd_nginx.cfg | head -1 | sed 's/^\s*//' | cut -d" " -f2 | cut -d";" -f1) - SET_LISTEN_PORT=$DEFAULT_PORT - fi - SET_NGINX_CFG="true" - else - SET_NGINX_CFG="false" - fi -} - -select_fluidd_port(){ - if [ "$PORT_80_BLOCKED" = "true" ]; then - echo - top_border - echo -e "| ${red}!!!WARNING!!!${default} |" - echo -e "| ${red}You need to choose a different port for Fluidd!${default} |" - echo -e "| ${red}The following web interface is listening at port 80:${default} |" - blank_line - [ "$OCTOPRINT_PORT" = "80" ] && echo "| ● OctoPrint |" - [ "$MAINSAIL_PORT" = "80" ] && echo "| ● Mainsail |" - [ "$DWC2_PORT" = "80" ] && echo "| ● DWC2 |" - blank_line - echo -e "| Make sure you don't choose a port which was already |" - echo -e "| assigned to one of the other web interfaces! |" - blank_line - echo -e "| Be aware: there is ${red}NO${default} sanity check for the following |" - echo -e "| input. So make sure to choose a valid port! |" - bottom_border - while true; do - read -p "${cyan}Please enter a new Port:${default} " NEW_PORT - if [ "$NEW_PORT" != "$MAINSAIL_PORT" ] && [ "$NEW_PORT" != "$DWC2_PORT" ] && [ "$NEW_PORT" != "$OCTOPRINT_PORT" ]; then - echo "Setting port $NEW_PORT for Fluidd!" - SET_LISTEN_PORT=$NEW_PORT - break - else - echo "That port is already taken! Select a different one!" - fi - done - fi -} - -get_fluidd_ver(){ - FLUIDD_VERSION=$(curl -s https://api.github.com/repositories/295836951/releases/latest | grep tag_name | cut -d'"' -f4 | cut -d"v" -f2) -} - -fluidd_setup(){ - #get fluidd download url - FLUIDD_DL_URL=$(curl -s https://api.github.com/repositories/295836951/releases/latest | grep browser_download_url | cut -d'"' -f4) - #clean up an existing fluidd folder - [ -d $FLUIDD_DIR ] && rm -rf $FLUIDD_DIR - #create fresh fluidd folder and download fluidd - mkdir $FLUIDD_DIR && cd $FLUIDD_DIR - status_msg "Downloading Fluidd $FLUIDD_VERSION ..." - wget $FLUIDD_DL_URL && ok_msg "Download complete!" - #extract archive - status_msg "Unzipping archive ..." - unzip -q -o *.zip && ok_msg "Done!" - #write fluidd version to file for update check reasons - status_msg "Writing Fluidd version to file ..." - get_fluidd_ver && echo $FLUIDD_VERSION > $FLUIDD_DIR/version && ok_msg "Done!" - #delete downloaded zip - status_msg "Do a little cleanup ..." - rm -rf *.zip && ok_msg "Done!" && ok_msg "Fluidd installation complete!" - echo -} \ No newline at end of file diff --git a/scripts/install_klipper_webui.sh b/scripts/install_klipper_webui.sh new file mode 100755 index 0000000..4c6822a --- /dev/null +++ b/scripts/install_klipper_webui.sh @@ -0,0 +1,246 @@ +check_moonraker(){ + status_msg "Checking for Moonraker service ..." + if [ "$(systemctl list-units --full -all -t service --no-legend | grep -F "moonraker.service")" ]; then + ok_msg "Moonraker service found!"; echo + MOONRAKER_SERVICE_FOUND="true" + else + warn_msg "Moonraker service not found!" + warn_msg "Please install Moonraker first!"; echo + MOONRAKER_SERVICE_FOUND="false" + fi +} + +get_user_selection_webui(){ + #ask user for webui default macros + while true; do + unset ADD_WEBUI_MACROS + echo + top_border + echo -e "| It is recommended to have some important macros to |" + echo -e "| have full functionality of the web interface. |" + blank_line + echo -e "| If you do not have such macros, you can choose to |" + echo -e "| install the suggested default macros now. |" + bottom_border + read -p "${cyan}###### Add the recommended macros? (Y/n):${default} " yn + case "$yn" in + Y|y|Yes|yes|"") + echo -e "###### > Yes" + ADD_WEBUI_MACROS="true" + break;; + N|n|No|no) + echo -e "###### > No" + ADD_WEBUI_MACROS="false" + break;; + *) + print_unkown_cmd + print_msg && clear_msg;; + esac + done +} + +install_mainsail(){ + get_user_selection_webui + #check if moonraker is already installed + check_moonraker + if [ "$MOONRAKER_SERVICE_FOUND" = "true" ]; then + #check for other enabled web interfaces + unset SET_LISTEN_PORT + detect_enabled_sites + #check if another site already listens to port 80 + mainsail_port_check + #creating the mainsail nginx cfg + set_nginx_cfg "mainsail" + test_nginx "$SET_LISTEN_PORT" + locate_printer_cfg && read_printer_cfg "mainsail" + install_webui_macros + mainsail_setup + fi +} + +install_fluidd(){ + get_user_selection_webui + #check if moonraker is already installed + check_moonraker + if [ "$MOONRAKER_SERVICE_FOUND" = "true" ]; then + #check for other enabled web interfaces + unset SET_LISTEN_PORT + detect_enabled_sites + #check if another site already listens to port 80 + fluidd_port_check + #creating the fluidd nginx cfg + set_nginx_cfg "fluidd" + test_nginx "$SET_LISTEN_PORT" + locate_printer_cfg && read_printer_cfg "fluidd" + install_webui_macros + fluidd_setup + fi +} + +install_webui_macros(){ + #copy webui_macros.cfg + if [ "$ADD_WEBUI_MACROS" = "true" ]; then + status_msg "Create webui_macros.cfg ..." + if [ ! -f ${HOME}/klipper_config/webui_macros.cfg ]; then + cp ${HOME}/kiauh/resources/webui_macros.cfg ${HOME}/klipper_config + ok_msg "File created!" + else + warn_msg "File already exists! Skipping ..." + fi + fi + write_printer_cfg +} + +mainsail_port_check(){ + if [ "$MAINSAIL_ENABLED" = "false" ]; then + if [ "$SITE_ENABLED" = "true" ]; then + status_msg "Detected other enabled interfaces:" + [ "$OCTOPRINT_ENABLED" = "true" ] && echo -e " ${cyan}● OctoPrint - Port: $OCTOPRINT_PORT${default}" + [ "$FLUIDD_ENABLED" = "true" ] && echo -e " ${cyan}● Fluidd - Port: $FLUIDD_PORT${default}" + [ "$DWC2_ENABLED" = "true" ] && echo -e " ${cyan}● DWC2 - Port: $DWC2_PORT${default}" + if [ "$FLUIDD_PORT" = "80" ] || [ "$DWC2_PORT" = "80" ] || [ "$OCTOPRINT_PORT" = "80" ]; then + PORT_80_BLOCKED="true" + select_mainsail_port + fi + else + DEFAULT_PORT=$(grep listen ${SRCDIR}/kiauh/resources/mainsail_nginx.cfg | head -1 | sed 's/^\s*//' | cut -d" " -f2 | cut -d";" -f1) + SET_LISTEN_PORT=$DEFAULT_PORT + fi + SET_NGINX_CFG="true" + else + SET_NGINX_CFG="false" + fi +} + +fluidd_port_check(){ + if [ "$FLUIDD_ENABLED" = "false" ]; then + if [ "$SITE_ENABLED" = "true" ]; then + status_msg "Detected other enabled interfaces:" + [ "$OCTOPRINT_ENABLED" = "true" ] && echo " ${cyan}● OctoPrint - Port: $OCTOPRINT_PORT${default}" + [ "$MAINSAIL_ENABLED" = "true" ] && echo " ${cyan}● Mainsail - Port: $MAINSAIL_PORT${default}" + [ "$DWC2_ENABLED" = "true" ] && echo " ${cyan}● DWC2 - Port: $DWC2_PORT${default}" + if [ "$MAINSAIL_PORT" = "80" ] || [ "$DWC2_PORT" = "80" ] || [ "$OCTOPRINT_PORT" = "80" ]; then + PORT_80_BLOCKED="true" + select_fluidd_port + fi + else + DEFAULT_PORT=$(grep listen ${SRCDIR}/kiauh/resources/fluidd_nginx.cfg | head -1 | sed 's/^\s*//' | cut -d" " -f2 | cut -d";" -f1) + SET_LISTEN_PORT=$DEFAULT_PORT + fi + SET_NGINX_CFG="true" + else + SET_NGINX_CFG="false" + fi +} + +select_mainsail_port(){ + if [ "$PORT_80_BLOCKED" = "true" ]; then + echo + top_border + echo -e "| ${red}!!!WARNING!!!${default} |" + echo -e "| ${red}You need to choose a different port for Mainsail!${default} |" + echo -e "| ${red}The following web interface is listening at port 80:${default} |" + blank_line + [ "$OCTOPRINT_PORT" = "80" ] && echo "| ● OctoPrint |" + [ "$FLUIDD_PORT" = "80" ] && echo "| ● Fluidd |" + [ "$DWC2_PORT" = "80" ] && echo "| ● DWC2 |" + blank_line + echo -e "| Make sure you don't choose a port which was already |" + echo -e "| assigned to one of the other web interfaces! |" + blank_line + echo -e "| Be aware: there is ${red}NO${default} sanity check for the following |" + echo -e "| input. So make sure to choose a valid port! |" + bottom_border + while true; do + read -p "${cyan}Please enter a new Port:${default} " NEW_PORT + if [ "$NEW_PORT" != "$FLUIDD_PORT" ] && [ "$NEW_PORT" != "$DWC2_PORT" ] && [ "$NEW_PORT" != "$OCTOPRINT_PORT" ]; then + echo "Setting port $NEW_PORT for Mainsail!" + SET_LISTEN_PORT=$NEW_PORT + break + else + echo "That port is already taken! Select a different one!" + fi + done + fi +} + +select_fluidd_port(){ + if [ "$PORT_80_BLOCKED" = "true" ]; then + echo + top_border + echo -e "| ${red}!!!WARNING!!!${default} |" + echo -e "| ${red}You need to choose a different port for Fluidd!${default} |" + echo -e "| ${red}The following web interface is listening at port 80:${default} |" + blank_line + [ "$OCTOPRINT_PORT" = "80" ] && echo "| ● OctoPrint |" + [ "$MAINSAIL_PORT" = "80" ] && echo "| ● Mainsail |" + [ "$DWC2_PORT" = "80" ] && echo "| ● DWC2 |" + blank_line + echo -e "| Make sure you don't choose a port which was already |" + echo -e "| assigned to one of the other web interfaces! |" + blank_line + echo -e "| Be aware: there is ${red}NO${default} sanity check for the following |" + echo -e "| input. So make sure to choose a valid port! |" + bottom_border + while true; do + read -p "${cyan}Please enter a new Port:${default} " NEW_PORT + if [ "$NEW_PORT" != "$MAINSAIL_PORT" ] && [ "$NEW_PORT" != "$DWC2_PORT" ] && [ "$NEW_PORT" != "$OCTOPRINT_PORT" ]; then + echo "Setting port $NEW_PORT for Fluidd!" + SET_LISTEN_PORT=$NEW_PORT + break + else + echo "That port is already taken! Select a different one!" + fi + done + fi +} + +get_mainsail_ver(){ + MAINSAIL_VERSION=$(curl -s https://api.github.com/repositories/240875926/releases | grep tag_name | cut -d'"' -f4 | cut -d"v" -f2 | head -1) +} + +get_fluidd_ver(){ + FLUIDD_VERSION=$(curl -s https://api.github.com/repositories/295836951/releases | grep tag_name | cut -d'"' -f4 | cut -d"v" -f2 | head -1) +} + +mainsail_setup(){ + #get mainsail download url + MAINSAIL_DL_URL=$(curl -s https://api.github.com/repositories/240875926/releases | grep browser_download_url | cut -d'"' -f4 | head -1) + #clean up an existing mainsail folder + [ -d $MAINSAIL_DIR ] && rm -rf $MAINSAIL_DIR + #create fresh mainsail folder and download mainsail + mkdir $MAINSAIL_DIR && cd $MAINSAIL_DIR + status_msg "Downloading Mainsail $MAINSAIL_VERSION ..." + wget $MAINSAIL_DL_URL && ok_msg "Download complete!" + #extract archive + status_msg "Extracting archive ..." + unzip -q -o *.zip && ok_msg "Done!" + ### write mainsail version to file for update check reasons + status_msg "Writing Mainsail version to file ..." + get_mainsail_ver && echo "$MAINSAIL_VERSION" > $MAINSAIL_DIR/version && ok_msg "Done!" + #delete downloaded zip + status_msg "Remove downloaded archive ..." + rm -rf *.zip && ok_msg "Done!" && ok_msg "Mainsail installation complete!" + echo +} + +fluidd_setup(){ + #get fluidd download url + FLUIDD_DL_URL=$(curl -s https://api.github.com/repositories/295836951/releases/latest | grep browser_download_url | cut -d'"' -f4) + #clean up an existing fluidd folder + [ -d $FLUIDD_DIR ] && rm -rf $FLUIDD_DIR + #create fresh fluidd folder and download fluidd + mkdir $FLUIDD_DIR && cd $FLUIDD_DIR + status_msg "Downloading Fluidd $FLUIDD_VERSION ..." + wget $FLUIDD_DL_URL && ok_msg "Download complete!" + #extract archive + status_msg "Extracting archive ..." + unzip -q -o *.zip && ok_msg "Done!" + #write fluidd version to file for update check reasons + status_msg "Writing Fluidd version to file ..." + get_fluidd_ver && echo $FLUIDD_VERSION > $FLUIDD_DIR/version && ok_msg "Done!" + #delete downloaded zip + status_msg "Remove downloaded archive ..." + rm -rf *.zip && ok_msg "Done!" && ok_msg "Fluidd installation complete!" + echo +} \ No newline at end of file diff --git a/scripts/install_mainsail.sh b/scripts/install_mainsail.sh deleted file mode 100755 index cafd9d9..0000000 --- a/scripts/install_mainsail.sh +++ /dev/null @@ -1,103 +0,0 @@ -install_mainsail(){ - if [ "$INST_MAINSAIL" = "true" ]; then - #check if moonraker is already installed - check_moonraker - if [ "$MOONRAKER_SERVICE_FOUND" = "true" ]; then - #check for other enabled web interfaces - unset SET_LISTEN_PORT - detect_enabled_sites - #check if another site already listens to port 80 - mainsail_port_check - #creating the mainsail nginx cfg - set_nginx_cfg "mainsail" - test_nginx "$SET_LISTEN_PORT" - mainsail_setup && ok_msg "Mainsail installation complete!"; echo - fi - fi -} - -check_moonraker(){ - status_msg "Checking for Moonraker service ..." - if [ "$(systemctl list-units --full -all -t service --no-legend | grep -F "moonraker.service")" ]; then - ok_msg "Moonraker service found!"; echo - MOONRAKER_SERVICE_FOUND="true" - else - warn_msg "Moonraker service not found!" - warn_msg "Please install Moonraker first!"; echo - MOONRAKER_SERVICE_FOUND="false" - fi -} - -mainsail_port_check(){ - if [ "$MAINSAIL_ENABLED" = "false" ]; then - if [ "$SITE_ENABLED" = "true" ]; then - status_msg "Detected other enabled interfaces:" - [ "$OCTOPRINT_ENABLED" = "true" ] && echo -e " ${cyan}● OctoPrint - Port: $OCTOPRINT_PORT${default}" - [ "$FLUIDD_ENABLED" = "true" ] && echo -e " ${cyan}● Fluidd - Port: $FLUIDD_PORT${default}" - [ "$DWC2_ENABLED" = "true" ] && echo -e " ${cyan}● DWC2 - Port: $DWC2_PORT${default}" - if [ "$FLUIDD_PORT" = "80" ] || [ "$DWC2_PORT" = "80" ] || [ "$OCTOPRINT_PORT" = "80" ]; then - PORT_80_BLOCKED="true" - select_mainsail_port - fi - else - DEFAULT_PORT=$(grep listen ${SRCDIR}/kiauh/resources/mainsail_nginx.cfg | head -1 | sed 's/^\s*//' | cut -d" " -f2 | cut -d";" -f1) - SET_LISTEN_PORT=$DEFAULT_PORT - fi - SET_NGINX_CFG="true" - else - SET_NGINX_CFG="false" - fi -} - -select_mainsail_port(){ - if [ "$PORT_80_BLOCKED" = "true" ]; then - echo - top_border - echo -e "| ${red}!!!WARNING!!!${default} |" - echo -e "| ${red}You need to choose a different port for Mainsail!${default} |" - echo -e "| ${red}The following web interface is listening at port 80:${default} |" - blank_line - [ "$OCTOPRINT_PORT" = "80" ] && echo "| ● OctoPrint |" - [ "$FLUIDD_PORT" = "80" ] && echo "| ● Fluidd |" - [ "$DWC2_PORT" = "80" ] && echo "| ● DWC2 |" - blank_line - echo -e "| Make sure you don't choose a port which was already |" - echo -e "| assigned to one of the other web interfaces! |" - blank_line - echo -e "| Be aware: there is ${red}NO${default} sanity check for the following |" - echo -e "| input. So make sure to choose a valid port! |" - bottom_border - while true; do - read -p "${cyan}Please enter a new Port:${default} " NEW_PORT - if [ "$NEW_PORT" != "$FLUIDD_PORT" ] && [ "$NEW_PORT" != "$DWC2_PORT" ] && [ "$NEW_PORT" != "$OCTOPRINT_PORT" ]; then - echo "Setting port $NEW_PORT for Mainsail!" - SET_LISTEN_PORT=$NEW_PORT - break - else - echo "That port is already taken! Select a different one!" - fi - done - fi -} - -get_mainsail_ver(){ - MAINSAIL_VERSION=$(curl -s https://api.github.com/repositories/240875926/tags | grep name | cut -d'"' -f4 | cut -d"v" -f2 | head -1) -} - -mainsail_dl_url(){ - get_mainsail_ver - MAINSAIL_URL=https://github.com/meteyou/mainsail/releases/download/v$MAINSAIL_VERSION/mainsail-beta-$MAINSAIL_VERSION.zip -} - -mainsail_setup(){ - mainsail_dl_url - #clean up an existing mainsail folder - [ -d $MAINSAIL_DIR ] && rm -rf $MAINSAIL_DIR - #create fresh mainsail folder and download mainsail - mkdir $MAINSAIL_DIR && cd $MAINSAIL_DIR - status_msg "Downloading Mainsail v$MAINSAIL_VERSION ..." - wget -O mainsail.zip $MAINSAIL_URL && status_msg "Extracting archive ..." && unzip -o mainsail.zip && rm mainsail.zip - ### write mainsail version to file for update check reasons - echo "$MAINSAIL_VERSION" > $MAINSAIL_DIR/version - echo -} \ No newline at end of file diff --git a/scripts/install_moonraker.sh b/scripts/install_moonraker.sh index 005e006..a6431e9 100755 --- a/scripts/install_moonraker.sh +++ b/scripts/install_moonraker.sh @@ -8,13 +8,12 @@ install_moonraker(){ moonraker_setup check_for_folder_moonraker #setup configs - setup_printer_config_mainsail + setup_printer_config_moonraker setup_moonraker_conf #execute customizations write_custom_trusted_clients symlinks_moonraker disable_octoprint - set_hostname #after install actions restart_moonraker restart_klipper @@ -32,17 +31,9 @@ system_check_moonraker(){ PRINTER_CFG_FOUND="false" fi #check for existing klippy.log symlink in /klipper_config - if [ ! -e ${HOME}/klipper_config/klippy.log ]; then - KLIPPY_SL_FOUND="false" - else - KLIPPY_SL_FOUND="true" - fi + [ ! -e ${HOME}/klipper_config/klippy.log ] && KLIPPY_SL_FOUND="false" #check for existing moonraker.log symlink in /klipper_config - if [ ! -e ${HOME}/klipper_config/moonraker.log ]; then - MOONRAKER_SL_FOUND="false" - else - MOONRAKER_SL_FOUND="true" - fi + [ ! -e ${HOME}/klipper_config/moonraker.log ] && MOONRAKER_SL_FOUND="false" #check for existing moonraker.conf if [ ! -f ${HOME}/moonraker.conf ]; then MOONRAKER_CONF_FOUND="false" @@ -55,13 +46,9 @@ system_check_moonraker(){ OCTOPRINT_ENABLED="true" fi #check if haproxy is installed - if [[ $(dpkg-query -f'${Status}' --show haproxy 2>/dev/null) = *\ installed ]]; then - HAPROXY_FOUND="true" - fi + [[ $(dpkg-query -f'${Status}' --show haproxy 2>/dev/null) = *\ installed ]] && HAPROXY_FOUND="true" #check if lighttpd is installed - if [[ $(dpkg-query -f'${Status}' --show lighttpd 2>/dev/null) = *\ installed ]]; then - LIGHTTPD_FOUND="true" - fi + [[ $(dpkg-query -f'${Status}' --show lighttpd 2>/dev/null) = *\ installed ]] && LIGHTTPD_FOUND="true" } get_user_selections_moonraker(){ @@ -158,25 +145,6 @@ get_user_selections_moonraker(){ print_msg && clear_msg;; esac done - #ask user for mainsail default macros - while true; do - unset ADD_MS_MACROS - echo - read -p "${cyan}###### Add the recommended Mainsail macros? (Y/n):${default} " yn - case "$yn" in - Y|y|Yes|yes|"") - echo -e "###### > Yes" - ADD_MS_MACROS="true" - break;; - N|n|No|no) - echo -e "###### > No" - ADD_MS_MACROS="false" - break;; - *) - print_unkown_cmd - print_msg && clear_msg;; - esac - done #ask user to disable octoprint when such installed service was found if [ "$OCTOPRINT_ENABLED" = "true" ]; then unset DISABLE_OPRINT @@ -274,9 +242,6 @@ moonraker_setup(){ dep=(wget curl unzip dfu-util nginx) dependency_check status_msg "Downloading Moonraker ..." - if [ -d $MOONRAKER_DIR ]; then - mv -f $MOONRAKER_DIR ${HOME}/moonraker_bak - fi cd ${HOME} && git clone $MOONRAKER_REPO ok_msg "Download complete!" status_msg "Installing Moonraker ..." @@ -354,7 +319,7 @@ check_for_folder_moonraker(){ ############################################################# ############################################################# -setup_printer_config_mainsail(){ +setup_printer_config_moonraker(){ if [ "$PRINTER_CFG_FOUND" = "true" ]; then backup_printer_cfg #copy printer.cfg to new location if @@ -365,34 +330,20 @@ setup_printer_config_mainsail(){ ok_msg "printer.cfg location: '$PRINTER_CFG'" ok_msg "Done!" fi - #check printer.cfg for necessary mainsail entries - read_printer_cfg_mainsail - write_printer_cfg_mainsail + #check printer.cfg for necessary moonraker entries + read_printer_cfg "moonraker" + write_printer_cfg fi if [ "$SEL_DEF_CFG" = "true" ]; then status_msg "Creating minimal default printer.cfg ..." - create_default_mainsail_printer_cfg + create_default_moonraker_printer_cfg ok_msg "printer.cfg location: '$PRINTER_CFG'" ok_msg "Done!" fi - #copy mainsail_macro.cfg - if [ "$ADD_MS_MACROS" = "true" ]; then - status_msg "Create mainsail_macros.cfg ..." - if [ ! -f ${HOME}/klipper_config/mainsail_macros.cfg ]; then - cp ${HOME}/kiauh/resources/mainsail_macros.cfg ${HOME}/klipper_config - ok_msg "File created!" - else - warn_msg "File does already exist! Skipping ..." - fi - fi } -read_printer_cfg_mainsail(){ +sc_check(){ SC="#*# <---------------------- SAVE_CONFIG ---------------------->" - [ ! "$(grep '^\[virtual_sdcard\]$' $PRINTER_CFG)" ] && VSD="false" - [ ! "$(grep '^\[pause_resume\]$' $PRINTER_CFG)" ] && PAUSE_RESUME="false" - [ ! "$(grep '^\[display_status\]$' $PRINTER_CFG)" ] && DISPLAY_STATUS="false" - [ ! "$(grep '^\[include mainsail_macros\.cfg\]$' $PRINTER_CFG)" ] && MS_MACRO="false" #check for a SAVE_CONFIG entry if [[ $(grep "$SC" $PRINTER_CFG) ]]; then SC_LINE=$(grep -n "$SC" $PRINTER_CFG | cut -d ":" -f1) @@ -403,39 +354,39 @@ read_printer_cfg_mainsail(){ fi } -write_printer_cfg_mainsail(){ +read_printer_cfg(){ + echo "selected: $1" + echo "pre sc" + sc_check + echo "past sc" + if [ "$1" = "moonraker" ]; then + echo "$1" && echo "moonraker" + [ ! "$(grep '^\[virtual_sdcard\]$' $PRINTER_CFG)" ] && VSD="false" + [ ! "$(grep '^\[pause_resume\]$' $PRINTER_CFG)" ] && PAUSE_RESUME="false" + [ ! "$(grep '^\[display_status\]$' $PRINTER_CFG)" ] && DISPLAY_STATUS="false" + elif [ "$1" = "mainsail" ] || [ "$1" = "fluidd" ]; then + echo "$1" && echo "mainsail/fluidd" + [ ! "$(grep '^\[include webui_macros\.cfg\]$' $PRINTER_CFG)" ] && WEBUI_MACROS="false" + fi +} + +write_printer_cfg(){ unset write_entries - if [ "$MS_MACRO" = "false" ] && [ "$ADD_MS_MACROS" = "true" ]; then - write_entries+=("[include mainsail_macros.cfg]") - fi - if [ "$PAUSE_RESUME" = "false" ]; then - write_entries+=("[pause_resume]") - fi - if [ "$DISPLAY_STATUS" = "false" ]; then - write_entries+=("[display_status]") - fi - if [ "$VSD" = "false" ]; then - write_entries+=("[virtual_sdcard]\npath: ~/sdcard") - fi - if [ "${#write_entries[@]}" != "0" ]; then - write_entries+=("\\\n############################\n##### CREATED BY KIAUH #####\n############################") - write_entries=("############################\n" "${write_entries[@]}") - fi - #execute writing - status_msg "Writing to printer.cfg ..." - if [ "$SC_ENTRY" = "true" ]; then - PRE_SC_LINE="$(expr $SC_LINE - 1)a" - for entry in "${write_entries[@]}" - do - sed -i "$PRE_SC_LINE $entry" $PRINTER_CFG - done - fi - if [ "$SC_ENTRY" = "false" ]; then - LINE_COUNT="$(wc -l < $PRINTER_CFG)a" - for entry in "${write_entries[@]}" - do - sed -i "$LINE_COUNT $entry" $PRINTER_CFG - done + [ "$VSD" = "false" ] && write_entries+=("[virtual_sdcard]\npath: ~/sdcard") + [ "$PAUSE_RESUME" = "false" ] && write_entries+=("[pause_resume]") + [ "$DISPLAY_STATUS" = "false" ] && write_entries+=("[display_status]") + [ "$WEBUI_MACROS" = "false" ] && [ "$ADD_WEBUI_MACROS" = "true" ] && write_entries+=("[include webui_macros.cfg]") + [ "${#write_entries[@]}" != "0" ] && write_entries=("##### AUTOCREATED BY KIAUH #####" "${write_entries[@]}") + #write needed entries to kiauh.cfg + for entry in "${write_entries[@]}"; do echo -e "$entry" >> ~/klipper_config/kiauh.cfg; done + #execute writing to printer.cfg + if [ ! "$(grep '^\[include kiauh\.cfg\]$' $PRINTER_CFG)" ]; then + status_msg "Writing [include kiauh.cfg] to printer.cfg ..." + [ "$SC_ENTRY" = "false" ] && echo -e "\n\n[include kiauh.cfg]\c" >> $PRINTER_CFG + if [ "$SC_ENTRY" = "true" ]; then + PRE_SC_LINE="$(expr $SC_LINE - 1)a" + sed -i "$PRE_SC_LINE [include kiauh.cfg]" $PRINTER_CFG + fi fi ok_msg "Done!" } @@ -479,23 +430,16 @@ setup_moonraker_nginx_cfg(){ ############################################################# ############################################################# -create_default_mainsail_printer_cfg(){ +create_default_moonraker_printer_cfg(){ #create default config touch ${HOME}/klipper_config/printer.cfg cat <> ${HOME}/klipper_config/printer.cfg - -########################## -### CREATED WITH KIAUH ### -########################## +### AUTOCREATED WITH KIAUH ### [virtual_sdcard] path: ~/sdcard [pause_resume] [display_status] -[include mainsail_macros.cfg] - -########################## -########################## DEFAULT_CFG } diff --git a/scripts/ui/install_menu.sh b/scripts/ui/install_menu.sh index 3b0352a..2830bf4 100755 --- a/scripts/ui/install_menu.sh +++ b/scripts/ui/install_menu.sh @@ -43,13 +43,13 @@ install_menu(){ 4) clear print_header - INST_MAINSAIL="true" && install_mainsail + install_mainsail print_msg && clear_msg install_ui;; 5) clear print_header - INST_FLUIDD="true" && install_fluidd + install_fluidd print_msg && clear_msg install_ui;; 6) From 4ae696857fc0726c415f4be6251690cb5f4c2b28 Mon Sep 17 00:00:00 2001 From: th33xitus Date: Wed, 28 Oct 2020 23:16:24 +0100 Subject: [PATCH 2/8] fix: followup to 9fc7f41 --- scripts/install_moonraker.sh | 42 +++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/scripts/install_moonraker.sh b/scripts/install_moonraker.sh index a6431e9..73de3e9 100755 --- a/scripts/install_moonraker.sh +++ b/scripts/install_moonraker.sh @@ -46,9 +46,13 @@ system_check_moonraker(){ OCTOPRINT_ENABLED="true" fi #check if haproxy is installed - [[ $(dpkg-query -f'${Status}' --show haproxy 2>/dev/null) = *\ installed ]] && HAPROXY_FOUND="true" + if [[ $(dpkg-query -f'${Status}' --show haproxy 2>/dev/null) = *\ installed ]]; then + HAPROXY_FOUND="true" + fi #check if lighttpd is installed - [[ $(dpkg-query -f'${Status}' --show lighttpd 2>/dev/null) = *\ installed ]] && LIGHTTPD_FOUND="true" + if [[ $(dpkg-query -f'${Status}' --show lighttpd 2>/dev/null) = *\ installed ]]; then + LIGHTTPD_FOUND="true" + fi } get_user_selections_moonraker(){ @@ -254,8 +258,7 @@ moonraker_setup(){ patch_klipper_sysfile #re-run printer.cfg location function to read the new path for the printer.cfg locate_printer_cfg - echo - ok_msg "Moonraker successfully installed!" + echo; ok_msg "Moonraker successfully installed!" } patch_klipper_sysfile(){ @@ -355,30 +358,35 @@ sc_check(){ } read_printer_cfg(){ - echo "selected: $1" - echo "pre sc" sc_check - echo "past sc" if [ "$1" = "moonraker" ]; then - echo "$1" && echo "moonraker" [ ! "$(grep '^\[virtual_sdcard\]$' $PRINTER_CFG)" ] && VSD="false" [ ! "$(grep '^\[pause_resume\]$' $PRINTER_CFG)" ] && PAUSE_RESUME="false" [ ! "$(grep '^\[display_status\]$' $PRINTER_CFG)" ] && DISPLAY_STATUS="false" elif [ "$1" = "mainsail" ] || [ "$1" = "fluidd" ]; then - echo "$1" && echo "mainsail/fluidd" [ ! "$(grep '^\[include webui_macros\.cfg\]$' $PRINTER_CFG)" ] && WEBUI_MACROS="false" fi } write_printer_cfg(){ - unset write_entries - [ "$VSD" = "false" ] && write_entries+=("[virtual_sdcard]\npath: ~/sdcard") - [ "$PAUSE_RESUME" = "false" ] && write_entries+=("[pause_resume]") - [ "$DISPLAY_STATUS" = "false" ] && write_entries+=("[display_status]") - [ "$WEBUI_MACROS" = "false" ] && [ "$ADD_WEBUI_MACROS" = "true" ] && write_entries+=("[include webui_macros.cfg]") - [ "${#write_entries[@]}" != "0" ] && write_entries=("##### AUTOCREATED BY KIAUH #####" "${write_entries[@]}") - #write needed entries to kiauh.cfg - for entry in "${write_entries[@]}"; do echo -e "$entry" >> ~/klipper_config/kiauh.cfg; done + #create kiauh.cfg if its needed and doesn't exist + if [ "$VSD" = "false" ] || [ "$PAUSE_RESUME" = "false" ] || [ "$DISPLAY_STATUS" = "false" ] || [ "$WEBUI_MACROS" = "false" ] && [ ! -f ~/klipper_config/kiauh.cfg ]; then + status_msg "Creating kiauh.cfg ..." + echo -e "##### AUTOCREATED BY KIAUH #####" > ~/klipper_config/kiauh.cfg + fi + #write each entry to kiauh.cfg if it doesn't exist + if [ "$VSD" = "false" ] && [[ ! $(grep '^\[virtual_sdcard\]$' ~/klipper_config/kiauh.cfg) ]]; then + echo -e "\n[virtual_sdcard]\npath: ~/sdcard\c" >> ~/klipper_config/kiauh.cfg + fi + if [ "$PAUSE_RESUME" = "false" ] && [[ ! $(grep '^\[pause_resume]$' ~/klipper_config/kiauh.cfg) ]]; then + echo -e "\n[pause_resume]\c" >> ~/klipper_config/kiauh.cfg + fi + if [ "$DISPLAY_STATUS" = "false" ] && [[ ! $(grep '^\[display_status]$' ~/klipper_config/kiauh.cfg) ]]; then + echo -e "\n[display_status]\c" >> ~/klipper_config/kiauh.cfg + fi + if [ "$WEBUI_MACROS" = "false" ] && [ "$ADD_WEBUI_MACROS" = "true" ] && [[ ! $(grep '^\[include webui_macros.cfg]$' ~/klipper_config/kiauh.cfg) ]]; then + echo -e "\n[include webui_macros.cfg]\c" >> ~/klipper_config/kiauh.cfg + fi #execute writing to printer.cfg if [ ! "$(grep '^\[include kiauh\.cfg\]$' $PRINTER_CFG)" ]; then status_msg "Writing [include kiauh.cfg] to printer.cfg ..." From b48319e24d36e70ce9d86abfbc90dc46db364e4c Mon Sep 17 00:00:00 2001 From: th33xitus Date: Wed, 28 Oct 2020 20:39:34 +0100 Subject: [PATCH 3/8] fix: rework klipper webui installers --- .../{mainsail_macros.cfg => webui_macros.cfg} | 12 +- scripts/install_fluidd.sh | 94 ------- scripts/install_klipper_webui.sh | 246 ++++++++++++++++++ scripts/install_mainsail.sh | 103 -------- scripts/install_moonraker.sh | 146 ++++------- scripts/ui/install_menu.sh | 4 +- 6 files changed, 295 insertions(+), 310 deletions(-) rename resources/{mainsail_macros.cfg => webui_macros.cfg} (74%) delete mode 100755 scripts/install_fluidd.sh create mode 100755 scripts/install_klipper_webui.sh delete mode 100755 scripts/install_mainsail.sh diff --git a/resources/mainsail_macros.cfg b/resources/webui_macros.cfg similarity index 74% rename from resources/mainsail_macros.cfg rename to resources/webui_macros.cfg index f89deda..5becc06 100644 --- a/resources/mainsail_macros.cfg +++ b/resources/webui_macros.cfg @@ -1,6 +1,4 @@ -########################## -### CREATED WITH KIAUH ### -########################## +### AUTOCREATED WITH KIAUH ### #is required to load the pause_resume module in klipper [pause_resume] @@ -31,14 +29,8 @@ gcode: [gcode_macro CANCEL_PRINT] rename_existing: BASE_CANCEL_PRINT -default_parameter_X: 230 #edit to your park position -default_parameter_Y: 230 #edit to your park position -default_parameter_Z: 10 #edit to your park position gcode: - M104 S0 - M140 S0 - M141 S0 - M106 S0 + TURN_OFF_HEATERS CLEAR_PAUSE SDCARD_RESET_FILE BASE_CANCEL_PRINT diff --git a/scripts/install_fluidd.sh b/scripts/install_fluidd.sh deleted file mode 100755 index 4af74fb..0000000 --- a/scripts/install_fluidd.sh +++ /dev/null @@ -1,94 +0,0 @@ -install_fluidd(){ - if [ "$INST_FLUIDD" = "true" ]; then - #check if moonraker is already installed - check_moonraker - if [ "$MOONRAKER_SERVICE_FOUND" = "true" ]; then - #check for other enabled web interfaces - unset SET_LISTEN_PORT - detect_enabled_sites - #check if another site already listens to port 80 - fluidd_port_check - #creating the fluidd nginx cfg - set_nginx_cfg "fluidd" - test_nginx "$SET_LISTEN_PORT" - fluidd_setup - fi - fi -} - -fluidd_port_check(){ - if [ "$FLUIDD_ENABLED" = "false" ]; then - if [ "$SITE_ENABLED" = "true" ]; then - status_msg "Detected other enabled interfaces:" - [ "$OCTOPRINT_ENABLED" = "true" ] && echo " ${cyan}● OctoPrint - Port: $OCTOPRINT_PORT${default}" - [ "$MAINSAIL_ENABLED" = "true" ] && echo " ${cyan}● Mainsail - Port: $MAINSAIL_PORT${default}" - [ "$DWC2_ENABLED" = "true" ] && echo " ${cyan}● DWC2 - Port: $DWC2_PORT${default}" - if [ "$MAINSAIL_PORT" = "80" ] || [ "$DWC2_PORT" = "80" ] || [ "$OCTOPRINT_PORT" = "80" ]; then - PORT_80_BLOCKED="true" - select_fluidd_port - fi - else - DEFAULT_PORT=$(grep listen ${SRCDIR}/kiauh/resources/fluidd_nginx.cfg | head -1 | sed 's/^\s*//' | cut -d" " -f2 | cut -d";" -f1) - SET_LISTEN_PORT=$DEFAULT_PORT - fi - SET_NGINX_CFG="true" - else - SET_NGINX_CFG="false" - fi -} - -select_fluidd_port(){ - if [ "$PORT_80_BLOCKED" = "true" ]; then - echo - top_border - echo -e "| ${red}!!!WARNING!!!${default} |" - echo -e "| ${red}You need to choose a different port for Fluidd!${default} |" - echo -e "| ${red}The following web interface is listening at port 80:${default} |" - blank_line - [ "$OCTOPRINT_PORT" = "80" ] && echo "| ● OctoPrint |" - [ "$MAINSAIL_PORT" = "80" ] && echo "| ● Mainsail |" - [ "$DWC2_PORT" = "80" ] && echo "| ● DWC2 |" - blank_line - echo -e "| Make sure you don't choose a port which was already |" - echo -e "| assigned to one of the other web interfaces! |" - blank_line - echo -e "| Be aware: there is ${red}NO${default} sanity check for the following |" - echo -e "| input. So make sure to choose a valid port! |" - bottom_border - while true; do - read -p "${cyan}Please enter a new Port:${default} " NEW_PORT - if [ "$NEW_PORT" != "$MAINSAIL_PORT" ] && [ "$NEW_PORT" != "$DWC2_PORT" ] && [ "$NEW_PORT" != "$OCTOPRINT_PORT" ]; then - echo "Setting port $NEW_PORT for Fluidd!" - SET_LISTEN_PORT=$NEW_PORT - break - else - echo "That port is already taken! Select a different one!" - fi - done - fi -} - -get_fluidd_ver(){ - FLUIDD_VERSION=$(curl -s https://api.github.com/repositories/295836951/releases/latest | grep tag_name | cut -d'"' -f4 | cut -d"v" -f2) -} - -fluidd_setup(){ - #get fluidd download url - FLUIDD_DL_URL=$(curl -s https://api.github.com/repositories/295836951/releases/latest | grep browser_download_url | cut -d'"' -f4) - #clean up an existing fluidd folder - [ -d $FLUIDD_DIR ] && rm -rf $FLUIDD_DIR - #create fresh fluidd folder and download fluidd - mkdir $FLUIDD_DIR && cd $FLUIDD_DIR - status_msg "Downloading Fluidd $FLUIDD_VERSION ..." - wget $FLUIDD_DL_URL && ok_msg "Download complete!" - #extract archive - status_msg "Unzipping archive ..." - unzip -q -o *.zip && ok_msg "Done!" - #write fluidd version to file for update check reasons - status_msg "Writing Fluidd version to file ..." - get_fluidd_ver && echo $FLUIDD_VERSION > $FLUIDD_DIR/version && ok_msg "Done!" - #delete downloaded zip - status_msg "Do a little cleanup ..." - rm -rf *.zip && ok_msg "Done!" && ok_msg "Fluidd installation complete!" - echo -} \ No newline at end of file diff --git a/scripts/install_klipper_webui.sh b/scripts/install_klipper_webui.sh new file mode 100755 index 0000000..4c6822a --- /dev/null +++ b/scripts/install_klipper_webui.sh @@ -0,0 +1,246 @@ +check_moonraker(){ + status_msg "Checking for Moonraker service ..." + if [ "$(systemctl list-units --full -all -t service --no-legend | grep -F "moonraker.service")" ]; then + ok_msg "Moonraker service found!"; echo + MOONRAKER_SERVICE_FOUND="true" + else + warn_msg "Moonraker service not found!" + warn_msg "Please install Moonraker first!"; echo + MOONRAKER_SERVICE_FOUND="false" + fi +} + +get_user_selection_webui(){ + #ask user for webui default macros + while true; do + unset ADD_WEBUI_MACROS + echo + top_border + echo -e "| It is recommended to have some important macros to |" + echo -e "| have full functionality of the web interface. |" + blank_line + echo -e "| If you do not have such macros, you can choose to |" + echo -e "| install the suggested default macros now. |" + bottom_border + read -p "${cyan}###### Add the recommended macros? (Y/n):${default} " yn + case "$yn" in + Y|y|Yes|yes|"") + echo -e "###### > Yes" + ADD_WEBUI_MACROS="true" + break;; + N|n|No|no) + echo -e "###### > No" + ADD_WEBUI_MACROS="false" + break;; + *) + print_unkown_cmd + print_msg && clear_msg;; + esac + done +} + +install_mainsail(){ + get_user_selection_webui + #check if moonraker is already installed + check_moonraker + if [ "$MOONRAKER_SERVICE_FOUND" = "true" ]; then + #check for other enabled web interfaces + unset SET_LISTEN_PORT + detect_enabled_sites + #check if another site already listens to port 80 + mainsail_port_check + #creating the mainsail nginx cfg + set_nginx_cfg "mainsail" + test_nginx "$SET_LISTEN_PORT" + locate_printer_cfg && read_printer_cfg "mainsail" + install_webui_macros + mainsail_setup + fi +} + +install_fluidd(){ + get_user_selection_webui + #check if moonraker is already installed + check_moonraker + if [ "$MOONRAKER_SERVICE_FOUND" = "true" ]; then + #check for other enabled web interfaces + unset SET_LISTEN_PORT + detect_enabled_sites + #check if another site already listens to port 80 + fluidd_port_check + #creating the fluidd nginx cfg + set_nginx_cfg "fluidd" + test_nginx "$SET_LISTEN_PORT" + locate_printer_cfg && read_printer_cfg "fluidd" + install_webui_macros + fluidd_setup + fi +} + +install_webui_macros(){ + #copy webui_macros.cfg + if [ "$ADD_WEBUI_MACROS" = "true" ]; then + status_msg "Create webui_macros.cfg ..." + if [ ! -f ${HOME}/klipper_config/webui_macros.cfg ]; then + cp ${HOME}/kiauh/resources/webui_macros.cfg ${HOME}/klipper_config + ok_msg "File created!" + else + warn_msg "File already exists! Skipping ..." + fi + fi + write_printer_cfg +} + +mainsail_port_check(){ + if [ "$MAINSAIL_ENABLED" = "false" ]; then + if [ "$SITE_ENABLED" = "true" ]; then + status_msg "Detected other enabled interfaces:" + [ "$OCTOPRINT_ENABLED" = "true" ] && echo -e " ${cyan}● OctoPrint - Port: $OCTOPRINT_PORT${default}" + [ "$FLUIDD_ENABLED" = "true" ] && echo -e " ${cyan}● Fluidd - Port: $FLUIDD_PORT${default}" + [ "$DWC2_ENABLED" = "true" ] && echo -e " ${cyan}● DWC2 - Port: $DWC2_PORT${default}" + if [ "$FLUIDD_PORT" = "80" ] || [ "$DWC2_PORT" = "80" ] || [ "$OCTOPRINT_PORT" = "80" ]; then + PORT_80_BLOCKED="true" + select_mainsail_port + fi + else + DEFAULT_PORT=$(grep listen ${SRCDIR}/kiauh/resources/mainsail_nginx.cfg | head -1 | sed 's/^\s*//' | cut -d" " -f2 | cut -d";" -f1) + SET_LISTEN_PORT=$DEFAULT_PORT + fi + SET_NGINX_CFG="true" + else + SET_NGINX_CFG="false" + fi +} + +fluidd_port_check(){ + if [ "$FLUIDD_ENABLED" = "false" ]; then + if [ "$SITE_ENABLED" = "true" ]; then + status_msg "Detected other enabled interfaces:" + [ "$OCTOPRINT_ENABLED" = "true" ] && echo " ${cyan}● OctoPrint - Port: $OCTOPRINT_PORT${default}" + [ "$MAINSAIL_ENABLED" = "true" ] && echo " ${cyan}● Mainsail - Port: $MAINSAIL_PORT${default}" + [ "$DWC2_ENABLED" = "true" ] && echo " ${cyan}● DWC2 - Port: $DWC2_PORT${default}" + if [ "$MAINSAIL_PORT" = "80" ] || [ "$DWC2_PORT" = "80" ] || [ "$OCTOPRINT_PORT" = "80" ]; then + PORT_80_BLOCKED="true" + select_fluidd_port + fi + else + DEFAULT_PORT=$(grep listen ${SRCDIR}/kiauh/resources/fluidd_nginx.cfg | head -1 | sed 's/^\s*//' | cut -d" " -f2 | cut -d";" -f1) + SET_LISTEN_PORT=$DEFAULT_PORT + fi + SET_NGINX_CFG="true" + else + SET_NGINX_CFG="false" + fi +} + +select_mainsail_port(){ + if [ "$PORT_80_BLOCKED" = "true" ]; then + echo + top_border + echo -e "| ${red}!!!WARNING!!!${default} |" + echo -e "| ${red}You need to choose a different port for Mainsail!${default} |" + echo -e "| ${red}The following web interface is listening at port 80:${default} |" + blank_line + [ "$OCTOPRINT_PORT" = "80" ] && echo "| ● OctoPrint |" + [ "$FLUIDD_PORT" = "80" ] && echo "| ● Fluidd |" + [ "$DWC2_PORT" = "80" ] && echo "| ● DWC2 |" + blank_line + echo -e "| Make sure you don't choose a port which was already |" + echo -e "| assigned to one of the other web interfaces! |" + blank_line + echo -e "| Be aware: there is ${red}NO${default} sanity check for the following |" + echo -e "| input. So make sure to choose a valid port! |" + bottom_border + while true; do + read -p "${cyan}Please enter a new Port:${default} " NEW_PORT + if [ "$NEW_PORT" != "$FLUIDD_PORT" ] && [ "$NEW_PORT" != "$DWC2_PORT" ] && [ "$NEW_PORT" != "$OCTOPRINT_PORT" ]; then + echo "Setting port $NEW_PORT for Mainsail!" + SET_LISTEN_PORT=$NEW_PORT + break + else + echo "That port is already taken! Select a different one!" + fi + done + fi +} + +select_fluidd_port(){ + if [ "$PORT_80_BLOCKED" = "true" ]; then + echo + top_border + echo -e "| ${red}!!!WARNING!!!${default} |" + echo -e "| ${red}You need to choose a different port for Fluidd!${default} |" + echo -e "| ${red}The following web interface is listening at port 80:${default} |" + blank_line + [ "$OCTOPRINT_PORT" = "80" ] && echo "| ● OctoPrint |" + [ "$MAINSAIL_PORT" = "80" ] && echo "| ● Mainsail |" + [ "$DWC2_PORT" = "80" ] && echo "| ● DWC2 |" + blank_line + echo -e "| Make sure you don't choose a port which was already |" + echo -e "| assigned to one of the other web interfaces! |" + blank_line + echo -e "| Be aware: there is ${red}NO${default} sanity check for the following |" + echo -e "| input. So make sure to choose a valid port! |" + bottom_border + while true; do + read -p "${cyan}Please enter a new Port:${default} " NEW_PORT + if [ "$NEW_PORT" != "$MAINSAIL_PORT" ] && [ "$NEW_PORT" != "$DWC2_PORT" ] && [ "$NEW_PORT" != "$OCTOPRINT_PORT" ]; then + echo "Setting port $NEW_PORT for Fluidd!" + SET_LISTEN_PORT=$NEW_PORT + break + else + echo "That port is already taken! Select a different one!" + fi + done + fi +} + +get_mainsail_ver(){ + MAINSAIL_VERSION=$(curl -s https://api.github.com/repositories/240875926/releases | grep tag_name | cut -d'"' -f4 | cut -d"v" -f2 | head -1) +} + +get_fluidd_ver(){ + FLUIDD_VERSION=$(curl -s https://api.github.com/repositories/295836951/releases | grep tag_name | cut -d'"' -f4 | cut -d"v" -f2 | head -1) +} + +mainsail_setup(){ + #get mainsail download url + MAINSAIL_DL_URL=$(curl -s https://api.github.com/repositories/240875926/releases | grep browser_download_url | cut -d'"' -f4 | head -1) + #clean up an existing mainsail folder + [ -d $MAINSAIL_DIR ] && rm -rf $MAINSAIL_DIR + #create fresh mainsail folder and download mainsail + mkdir $MAINSAIL_DIR && cd $MAINSAIL_DIR + status_msg "Downloading Mainsail $MAINSAIL_VERSION ..." + wget $MAINSAIL_DL_URL && ok_msg "Download complete!" + #extract archive + status_msg "Extracting archive ..." + unzip -q -o *.zip && ok_msg "Done!" + ### write mainsail version to file for update check reasons + status_msg "Writing Mainsail version to file ..." + get_mainsail_ver && echo "$MAINSAIL_VERSION" > $MAINSAIL_DIR/version && ok_msg "Done!" + #delete downloaded zip + status_msg "Remove downloaded archive ..." + rm -rf *.zip && ok_msg "Done!" && ok_msg "Mainsail installation complete!" + echo +} + +fluidd_setup(){ + #get fluidd download url + FLUIDD_DL_URL=$(curl -s https://api.github.com/repositories/295836951/releases/latest | grep browser_download_url | cut -d'"' -f4) + #clean up an existing fluidd folder + [ -d $FLUIDD_DIR ] && rm -rf $FLUIDD_DIR + #create fresh fluidd folder and download fluidd + mkdir $FLUIDD_DIR && cd $FLUIDD_DIR + status_msg "Downloading Fluidd $FLUIDD_VERSION ..." + wget $FLUIDD_DL_URL && ok_msg "Download complete!" + #extract archive + status_msg "Extracting archive ..." + unzip -q -o *.zip && ok_msg "Done!" + #write fluidd version to file for update check reasons + status_msg "Writing Fluidd version to file ..." + get_fluidd_ver && echo $FLUIDD_VERSION > $FLUIDD_DIR/version && ok_msg "Done!" + #delete downloaded zip + status_msg "Remove downloaded archive ..." + rm -rf *.zip && ok_msg "Done!" && ok_msg "Fluidd installation complete!" + echo +} \ No newline at end of file diff --git a/scripts/install_mainsail.sh b/scripts/install_mainsail.sh deleted file mode 100755 index cafd9d9..0000000 --- a/scripts/install_mainsail.sh +++ /dev/null @@ -1,103 +0,0 @@ -install_mainsail(){ - if [ "$INST_MAINSAIL" = "true" ]; then - #check if moonraker is already installed - check_moonraker - if [ "$MOONRAKER_SERVICE_FOUND" = "true" ]; then - #check for other enabled web interfaces - unset SET_LISTEN_PORT - detect_enabled_sites - #check if another site already listens to port 80 - mainsail_port_check - #creating the mainsail nginx cfg - set_nginx_cfg "mainsail" - test_nginx "$SET_LISTEN_PORT" - mainsail_setup && ok_msg "Mainsail installation complete!"; echo - fi - fi -} - -check_moonraker(){ - status_msg "Checking for Moonraker service ..." - if [ "$(systemctl list-units --full -all -t service --no-legend | grep -F "moonraker.service")" ]; then - ok_msg "Moonraker service found!"; echo - MOONRAKER_SERVICE_FOUND="true" - else - warn_msg "Moonraker service not found!" - warn_msg "Please install Moonraker first!"; echo - MOONRAKER_SERVICE_FOUND="false" - fi -} - -mainsail_port_check(){ - if [ "$MAINSAIL_ENABLED" = "false" ]; then - if [ "$SITE_ENABLED" = "true" ]; then - status_msg "Detected other enabled interfaces:" - [ "$OCTOPRINT_ENABLED" = "true" ] && echo -e " ${cyan}● OctoPrint - Port: $OCTOPRINT_PORT${default}" - [ "$FLUIDD_ENABLED" = "true" ] && echo -e " ${cyan}● Fluidd - Port: $FLUIDD_PORT${default}" - [ "$DWC2_ENABLED" = "true" ] && echo -e " ${cyan}● DWC2 - Port: $DWC2_PORT${default}" - if [ "$FLUIDD_PORT" = "80" ] || [ "$DWC2_PORT" = "80" ] || [ "$OCTOPRINT_PORT" = "80" ]; then - PORT_80_BLOCKED="true" - select_mainsail_port - fi - else - DEFAULT_PORT=$(grep listen ${SRCDIR}/kiauh/resources/mainsail_nginx.cfg | head -1 | sed 's/^\s*//' | cut -d" " -f2 | cut -d";" -f1) - SET_LISTEN_PORT=$DEFAULT_PORT - fi - SET_NGINX_CFG="true" - else - SET_NGINX_CFG="false" - fi -} - -select_mainsail_port(){ - if [ "$PORT_80_BLOCKED" = "true" ]; then - echo - top_border - echo -e "| ${red}!!!WARNING!!!${default} |" - echo -e "| ${red}You need to choose a different port for Mainsail!${default} |" - echo -e "| ${red}The following web interface is listening at port 80:${default} |" - blank_line - [ "$OCTOPRINT_PORT" = "80" ] && echo "| ● OctoPrint |" - [ "$FLUIDD_PORT" = "80" ] && echo "| ● Fluidd |" - [ "$DWC2_PORT" = "80" ] && echo "| ● DWC2 |" - blank_line - echo -e "| Make sure you don't choose a port which was already |" - echo -e "| assigned to one of the other web interfaces! |" - blank_line - echo -e "| Be aware: there is ${red}NO${default} sanity check for the following |" - echo -e "| input. So make sure to choose a valid port! |" - bottom_border - while true; do - read -p "${cyan}Please enter a new Port:${default} " NEW_PORT - if [ "$NEW_PORT" != "$FLUIDD_PORT" ] && [ "$NEW_PORT" != "$DWC2_PORT" ] && [ "$NEW_PORT" != "$OCTOPRINT_PORT" ]; then - echo "Setting port $NEW_PORT for Mainsail!" - SET_LISTEN_PORT=$NEW_PORT - break - else - echo "That port is already taken! Select a different one!" - fi - done - fi -} - -get_mainsail_ver(){ - MAINSAIL_VERSION=$(curl -s https://api.github.com/repositories/240875926/tags | grep name | cut -d'"' -f4 | cut -d"v" -f2 | head -1) -} - -mainsail_dl_url(){ - get_mainsail_ver - MAINSAIL_URL=https://github.com/meteyou/mainsail/releases/download/v$MAINSAIL_VERSION/mainsail-beta-$MAINSAIL_VERSION.zip -} - -mainsail_setup(){ - mainsail_dl_url - #clean up an existing mainsail folder - [ -d $MAINSAIL_DIR ] && rm -rf $MAINSAIL_DIR - #create fresh mainsail folder and download mainsail - mkdir $MAINSAIL_DIR && cd $MAINSAIL_DIR - status_msg "Downloading Mainsail v$MAINSAIL_VERSION ..." - wget -O mainsail.zip $MAINSAIL_URL && status_msg "Extracting archive ..." && unzip -o mainsail.zip && rm mainsail.zip - ### write mainsail version to file for update check reasons - echo "$MAINSAIL_VERSION" > $MAINSAIL_DIR/version - echo -} \ No newline at end of file diff --git a/scripts/install_moonraker.sh b/scripts/install_moonraker.sh index 005e006..a6431e9 100755 --- a/scripts/install_moonraker.sh +++ b/scripts/install_moonraker.sh @@ -8,13 +8,12 @@ install_moonraker(){ moonraker_setup check_for_folder_moonraker #setup configs - setup_printer_config_mainsail + setup_printer_config_moonraker setup_moonraker_conf #execute customizations write_custom_trusted_clients symlinks_moonraker disable_octoprint - set_hostname #after install actions restart_moonraker restart_klipper @@ -32,17 +31,9 @@ system_check_moonraker(){ PRINTER_CFG_FOUND="false" fi #check for existing klippy.log symlink in /klipper_config - if [ ! -e ${HOME}/klipper_config/klippy.log ]; then - KLIPPY_SL_FOUND="false" - else - KLIPPY_SL_FOUND="true" - fi + [ ! -e ${HOME}/klipper_config/klippy.log ] && KLIPPY_SL_FOUND="false" #check for existing moonraker.log symlink in /klipper_config - if [ ! -e ${HOME}/klipper_config/moonraker.log ]; then - MOONRAKER_SL_FOUND="false" - else - MOONRAKER_SL_FOUND="true" - fi + [ ! -e ${HOME}/klipper_config/moonraker.log ] && MOONRAKER_SL_FOUND="false" #check for existing moonraker.conf if [ ! -f ${HOME}/moonraker.conf ]; then MOONRAKER_CONF_FOUND="false" @@ -55,13 +46,9 @@ system_check_moonraker(){ OCTOPRINT_ENABLED="true" fi #check if haproxy is installed - if [[ $(dpkg-query -f'${Status}' --show haproxy 2>/dev/null) = *\ installed ]]; then - HAPROXY_FOUND="true" - fi + [[ $(dpkg-query -f'${Status}' --show haproxy 2>/dev/null) = *\ installed ]] && HAPROXY_FOUND="true" #check if lighttpd is installed - if [[ $(dpkg-query -f'${Status}' --show lighttpd 2>/dev/null) = *\ installed ]]; then - LIGHTTPD_FOUND="true" - fi + [[ $(dpkg-query -f'${Status}' --show lighttpd 2>/dev/null) = *\ installed ]] && LIGHTTPD_FOUND="true" } get_user_selections_moonraker(){ @@ -158,25 +145,6 @@ get_user_selections_moonraker(){ print_msg && clear_msg;; esac done - #ask user for mainsail default macros - while true; do - unset ADD_MS_MACROS - echo - read -p "${cyan}###### Add the recommended Mainsail macros? (Y/n):${default} " yn - case "$yn" in - Y|y|Yes|yes|"") - echo -e "###### > Yes" - ADD_MS_MACROS="true" - break;; - N|n|No|no) - echo -e "###### > No" - ADD_MS_MACROS="false" - break;; - *) - print_unkown_cmd - print_msg && clear_msg;; - esac - done #ask user to disable octoprint when such installed service was found if [ "$OCTOPRINT_ENABLED" = "true" ]; then unset DISABLE_OPRINT @@ -274,9 +242,6 @@ moonraker_setup(){ dep=(wget curl unzip dfu-util nginx) dependency_check status_msg "Downloading Moonraker ..." - if [ -d $MOONRAKER_DIR ]; then - mv -f $MOONRAKER_DIR ${HOME}/moonraker_bak - fi cd ${HOME} && git clone $MOONRAKER_REPO ok_msg "Download complete!" status_msg "Installing Moonraker ..." @@ -354,7 +319,7 @@ check_for_folder_moonraker(){ ############################################################# ############################################################# -setup_printer_config_mainsail(){ +setup_printer_config_moonraker(){ if [ "$PRINTER_CFG_FOUND" = "true" ]; then backup_printer_cfg #copy printer.cfg to new location if @@ -365,34 +330,20 @@ setup_printer_config_mainsail(){ ok_msg "printer.cfg location: '$PRINTER_CFG'" ok_msg "Done!" fi - #check printer.cfg for necessary mainsail entries - read_printer_cfg_mainsail - write_printer_cfg_mainsail + #check printer.cfg for necessary moonraker entries + read_printer_cfg "moonraker" + write_printer_cfg fi if [ "$SEL_DEF_CFG" = "true" ]; then status_msg "Creating minimal default printer.cfg ..." - create_default_mainsail_printer_cfg + create_default_moonraker_printer_cfg ok_msg "printer.cfg location: '$PRINTER_CFG'" ok_msg "Done!" fi - #copy mainsail_macro.cfg - if [ "$ADD_MS_MACROS" = "true" ]; then - status_msg "Create mainsail_macros.cfg ..." - if [ ! -f ${HOME}/klipper_config/mainsail_macros.cfg ]; then - cp ${HOME}/kiauh/resources/mainsail_macros.cfg ${HOME}/klipper_config - ok_msg "File created!" - else - warn_msg "File does already exist! Skipping ..." - fi - fi } -read_printer_cfg_mainsail(){ +sc_check(){ SC="#*# <---------------------- SAVE_CONFIG ---------------------->" - [ ! "$(grep '^\[virtual_sdcard\]$' $PRINTER_CFG)" ] && VSD="false" - [ ! "$(grep '^\[pause_resume\]$' $PRINTER_CFG)" ] && PAUSE_RESUME="false" - [ ! "$(grep '^\[display_status\]$' $PRINTER_CFG)" ] && DISPLAY_STATUS="false" - [ ! "$(grep '^\[include mainsail_macros\.cfg\]$' $PRINTER_CFG)" ] && MS_MACRO="false" #check for a SAVE_CONFIG entry if [[ $(grep "$SC" $PRINTER_CFG) ]]; then SC_LINE=$(grep -n "$SC" $PRINTER_CFG | cut -d ":" -f1) @@ -403,39 +354,39 @@ read_printer_cfg_mainsail(){ fi } -write_printer_cfg_mainsail(){ +read_printer_cfg(){ + echo "selected: $1" + echo "pre sc" + sc_check + echo "past sc" + if [ "$1" = "moonraker" ]; then + echo "$1" && echo "moonraker" + [ ! "$(grep '^\[virtual_sdcard\]$' $PRINTER_CFG)" ] && VSD="false" + [ ! "$(grep '^\[pause_resume\]$' $PRINTER_CFG)" ] && PAUSE_RESUME="false" + [ ! "$(grep '^\[display_status\]$' $PRINTER_CFG)" ] && DISPLAY_STATUS="false" + elif [ "$1" = "mainsail" ] || [ "$1" = "fluidd" ]; then + echo "$1" && echo "mainsail/fluidd" + [ ! "$(grep '^\[include webui_macros\.cfg\]$' $PRINTER_CFG)" ] && WEBUI_MACROS="false" + fi +} + +write_printer_cfg(){ unset write_entries - if [ "$MS_MACRO" = "false" ] && [ "$ADD_MS_MACROS" = "true" ]; then - write_entries+=("[include mainsail_macros.cfg]") - fi - if [ "$PAUSE_RESUME" = "false" ]; then - write_entries+=("[pause_resume]") - fi - if [ "$DISPLAY_STATUS" = "false" ]; then - write_entries+=("[display_status]") - fi - if [ "$VSD" = "false" ]; then - write_entries+=("[virtual_sdcard]\npath: ~/sdcard") - fi - if [ "${#write_entries[@]}" != "0" ]; then - write_entries+=("\\\n############################\n##### CREATED BY KIAUH #####\n############################") - write_entries=("############################\n" "${write_entries[@]}") - fi - #execute writing - status_msg "Writing to printer.cfg ..." - if [ "$SC_ENTRY" = "true" ]; then - PRE_SC_LINE="$(expr $SC_LINE - 1)a" - for entry in "${write_entries[@]}" - do - sed -i "$PRE_SC_LINE $entry" $PRINTER_CFG - done - fi - if [ "$SC_ENTRY" = "false" ]; then - LINE_COUNT="$(wc -l < $PRINTER_CFG)a" - for entry in "${write_entries[@]}" - do - sed -i "$LINE_COUNT $entry" $PRINTER_CFG - done + [ "$VSD" = "false" ] && write_entries+=("[virtual_sdcard]\npath: ~/sdcard") + [ "$PAUSE_RESUME" = "false" ] && write_entries+=("[pause_resume]") + [ "$DISPLAY_STATUS" = "false" ] && write_entries+=("[display_status]") + [ "$WEBUI_MACROS" = "false" ] && [ "$ADD_WEBUI_MACROS" = "true" ] && write_entries+=("[include webui_macros.cfg]") + [ "${#write_entries[@]}" != "0" ] && write_entries=("##### AUTOCREATED BY KIAUH #####" "${write_entries[@]}") + #write needed entries to kiauh.cfg + for entry in "${write_entries[@]}"; do echo -e "$entry" >> ~/klipper_config/kiauh.cfg; done + #execute writing to printer.cfg + if [ ! "$(grep '^\[include kiauh\.cfg\]$' $PRINTER_CFG)" ]; then + status_msg "Writing [include kiauh.cfg] to printer.cfg ..." + [ "$SC_ENTRY" = "false" ] && echo -e "\n\n[include kiauh.cfg]\c" >> $PRINTER_CFG + if [ "$SC_ENTRY" = "true" ]; then + PRE_SC_LINE="$(expr $SC_LINE - 1)a" + sed -i "$PRE_SC_LINE [include kiauh.cfg]" $PRINTER_CFG + fi fi ok_msg "Done!" } @@ -479,23 +430,16 @@ setup_moonraker_nginx_cfg(){ ############################################################# ############################################################# -create_default_mainsail_printer_cfg(){ +create_default_moonraker_printer_cfg(){ #create default config touch ${HOME}/klipper_config/printer.cfg cat <> ${HOME}/klipper_config/printer.cfg - -########################## -### CREATED WITH KIAUH ### -########################## +### AUTOCREATED WITH KIAUH ### [virtual_sdcard] path: ~/sdcard [pause_resume] [display_status] -[include mainsail_macros.cfg] - -########################## -########################## DEFAULT_CFG } diff --git a/scripts/ui/install_menu.sh b/scripts/ui/install_menu.sh index 4dc97b9..8fbefc0 100755 --- a/scripts/ui/install_menu.sh +++ b/scripts/ui/install_menu.sh @@ -41,13 +41,13 @@ install_menu(){ 4) clear print_header - INST_MAINSAIL="true" && install_mainsail + install_mainsail print_msg && clear_msg install_ui;; 5) clear print_header - INST_FLUIDD="true" && install_fluidd + install_fluidd print_msg && clear_msg install_ui;; 6) From 55382b1ecb3f81e0cfaa5a2a5958bb2122811686 Mon Sep 17 00:00:00 2001 From: th33xitus Date: Wed, 28 Oct 2020 23:16:24 +0100 Subject: [PATCH 4/8] fix: followup to 9fc7f41 --- scripts/install_moonraker.sh | 42 +++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/scripts/install_moonraker.sh b/scripts/install_moonraker.sh index a6431e9..73de3e9 100755 --- a/scripts/install_moonraker.sh +++ b/scripts/install_moonraker.sh @@ -46,9 +46,13 @@ system_check_moonraker(){ OCTOPRINT_ENABLED="true" fi #check if haproxy is installed - [[ $(dpkg-query -f'${Status}' --show haproxy 2>/dev/null) = *\ installed ]] && HAPROXY_FOUND="true" + if [[ $(dpkg-query -f'${Status}' --show haproxy 2>/dev/null) = *\ installed ]]; then + HAPROXY_FOUND="true" + fi #check if lighttpd is installed - [[ $(dpkg-query -f'${Status}' --show lighttpd 2>/dev/null) = *\ installed ]] && LIGHTTPD_FOUND="true" + if [[ $(dpkg-query -f'${Status}' --show lighttpd 2>/dev/null) = *\ installed ]]; then + LIGHTTPD_FOUND="true" + fi } get_user_selections_moonraker(){ @@ -254,8 +258,7 @@ moonraker_setup(){ patch_klipper_sysfile #re-run printer.cfg location function to read the new path for the printer.cfg locate_printer_cfg - echo - ok_msg "Moonraker successfully installed!" + echo; ok_msg "Moonraker successfully installed!" } patch_klipper_sysfile(){ @@ -355,30 +358,35 @@ sc_check(){ } read_printer_cfg(){ - echo "selected: $1" - echo "pre sc" sc_check - echo "past sc" if [ "$1" = "moonraker" ]; then - echo "$1" && echo "moonraker" [ ! "$(grep '^\[virtual_sdcard\]$' $PRINTER_CFG)" ] && VSD="false" [ ! "$(grep '^\[pause_resume\]$' $PRINTER_CFG)" ] && PAUSE_RESUME="false" [ ! "$(grep '^\[display_status\]$' $PRINTER_CFG)" ] && DISPLAY_STATUS="false" elif [ "$1" = "mainsail" ] || [ "$1" = "fluidd" ]; then - echo "$1" && echo "mainsail/fluidd" [ ! "$(grep '^\[include webui_macros\.cfg\]$' $PRINTER_CFG)" ] && WEBUI_MACROS="false" fi } write_printer_cfg(){ - unset write_entries - [ "$VSD" = "false" ] && write_entries+=("[virtual_sdcard]\npath: ~/sdcard") - [ "$PAUSE_RESUME" = "false" ] && write_entries+=("[pause_resume]") - [ "$DISPLAY_STATUS" = "false" ] && write_entries+=("[display_status]") - [ "$WEBUI_MACROS" = "false" ] && [ "$ADD_WEBUI_MACROS" = "true" ] && write_entries+=("[include webui_macros.cfg]") - [ "${#write_entries[@]}" != "0" ] && write_entries=("##### AUTOCREATED BY KIAUH #####" "${write_entries[@]}") - #write needed entries to kiauh.cfg - for entry in "${write_entries[@]}"; do echo -e "$entry" >> ~/klipper_config/kiauh.cfg; done + #create kiauh.cfg if its needed and doesn't exist + if [ "$VSD" = "false" ] || [ "$PAUSE_RESUME" = "false" ] || [ "$DISPLAY_STATUS" = "false" ] || [ "$WEBUI_MACROS" = "false" ] && [ ! -f ~/klipper_config/kiauh.cfg ]; then + status_msg "Creating kiauh.cfg ..." + echo -e "##### AUTOCREATED BY KIAUH #####" > ~/klipper_config/kiauh.cfg + fi + #write each entry to kiauh.cfg if it doesn't exist + if [ "$VSD" = "false" ] && [[ ! $(grep '^\[virtual_sdcard\]$' ~/klipper_config/kiauh.cfg) ]]; then + echo -e "\n[virtual_sdcard]\npath: ~/sdcard\c" >> ~/klipper_config/kiauh.cfg + fi + if [ "$PAUSE_RESUME" = "false" ] && [[ ! $(grep '^\[pause_resume]$' ~/klipper_config/kiauh.cfg) ]]; then + echo -e "\n[pause_resume]\c" >> ~/klipper_config/kiauh.cfg + fi + if [ "$DISPLAY_STATUS" = "false" ] && [[ ! $(grep '^\[display_status]$' ~/klipper_config/kiauh.cfg) ]]; then + echo -e "\n[display_status]\c" >> ~/klipper_config/kiauh.cfg + fi + if [ "$WEBUI_MACROS" = "false" ] && [ "$ADD_WEBUI_MACROS" = "true" ] && [[ ! $(grep '^\[include webui_macros.cfg]$' ~/klipper_config/kiauh.cfg) ]]; then + echo -e "\n[include webui_macros.cfg]\c" >> ~/klipper_config/kiauh.cfg + fi #execute writing to printer.cfg if [ ! "$(grep '^\[include kiauh\.cfg\]$' $PRINTER_CFG)" ]; then status_msg "Writing [include kiauh.cfg] to printer.cfg ..." From 9ecf7068f10707d7ed251c73ad31e2b219d0d7ce Mon Sep 17 00:00:00 2001 From: th33xitus Date: Thu, 29 Oct 2020 22:28:24 +0100 Subject: [PATCH 5/8] fix: rework of writing to configs --- scripts/functions.sh | 101 +++++++++++++++++++++++------------ scripts/install_moonraker.sh | 54 ------------------- 2 files changed, 68 insertions(+), 87 deletions(-) diff --git a/scripts/functions.sh b/scripts/functions.sh index 273e8c2..fea7f28 100755 --- a/scripts/functions.sh +++ b/scripts/functions.sh @@ -238,47 +238,82 @@ setup_gcode_shell_command(){ install_gcode_shell_command(){ stop_klipper + status_msg "Copy 'gcode_shell_command.py' to $KLIPPER_DIR/klippy/extras" cp ${HOME}/kiauh/resources/gcode_shell_command.py $KLIPPER_DIR/klippy/extras - status_msg "Creating example macro ..." - locate_printer_cfg - create_shell_command_example - ok_msg "Example macro created!" + echo + while true; do + read -p "${cyan}###### Do you want to create the example shell command? (Y/n):${default} " yn + case "$yn" in + Y|y|Yes|yes|"") + ADD_SHELL_CMD_MACRO="true" + status_msg "Creating example macro ..." + locate_printer_cfg + read_printer_cfg "gcode_shell_command" + write_printer_cfg + ok_msg "Example macro created!" + break;; + N|n|No|no) + break;; + esac + done ok_msg "Shell command extension installed!" restart_klipper } -create_shell_command_example(){ - unset SC_ENTRY - unset write_entries - #check for a SAVE_CONFIG entry - SC="#*# <---------------------- SAVE_CONFIG ---------------------->" - if [[ $(grep "$SC" $PRINTER_CFG) ]]; then - SC_LINE=$(grep -n "$SC" $PRINTER_CFG | cut -d ":" -f1) - PRE_SC_LINE=$(expr $SC_LINE - 1) - SC_ENTRY="true" - else - SC_ENTRY="false" +read_printer_cfg(){ + KIAUH_CFG=$(echo $PRINTER_CFG | sed 's/printer/kiauh/') + if [ "$1" = "gcode_shell_command" ]; then + [ ! -f $KIAUH_CFG ] && KIAUH_CFG_FOUND="false" || KIAUH_CFG_FOUND="true" + elif [ "$1" = "moonraker" ]; then + [ ! -f $KIAUH_CFG ] && KIAUH_CFG_FOUND="false" || KIAUH_CFG_FOUND="true" + [ ! "$(grep '^\[virtual_sdcard\]$' $PRINTER_CFG)" ] && VSD="false" + [ ! "$(grep '^\[pause_resume\]$' $PRINTER_CFG)" ] && PAUSE_RESUME="false" + [ ! "$(grep '^\[display_status\]$' $PRINTER_CFG)" ] && DISPLAY_STATUS="false" + elif [ "$1" = "mainsail" ] || [ "$1" = "fluidd" ]; then + [ ! -f $KIAUH_CFG ] && KIAUH_CFG_FOUND="false" || KIAUH_CFG_FOUND="true" + [ ! "$(grep '^\[include webui_macros\.cfg\]$' $PRINTER_CFG)" ] && WEBUI_MACROS="false" fi - #example shell command - write_entries+=("[shell_command hello_world]\ncommand: echo hello world\ntimeout: 2.\nverbose: True") - #example macro - write_entries+=("[gcode_macro HELLO_WORLD]\ngcode:\n RUN_SHELL_COMMAND CMD=hello_world") - #execute writing - status_msg "Writing to printer.cfg ..." - if [ "$SC_ENTRY" = "true" ]; then - PRE_SC_LINE="$(expr $SC_LINE - 1)a" - for entry in "${write_entries[@]}" - do - sed -i "$PRE_SC_LINE $entry" $PRINTER_CFG - done +} + +write_printer_cfg(){ + #create kiauh.cfg if its needed and doesn't exist + if [ "$KIAUH_CFG_FOUND" = "false" ]; then + status_msg "Creating kiauh.cfg ..." + echo -e "##### AUTOCREATED BY KIAUH #####\c" > $KIAUH_CFG fi - if [ "$SC_ENTRY" = "false" ]; then - LINE_COUNT="$(wc -l < $PRINTER_CFG)a" - for entry in "${write_entries[@]}" - do - sed -i "$LINE_COUNT $entry" $PRINTER_CFG - done + #write each entry to kiauh.cfg if it doesn't exist + #Moonraker related config options + if [ "$VSD" = "false" ] && [[ ! $(grep '^\[virtual_sdcard\]$' $KIAUH_CFG) ]]; then + echo -e "\n[virtual_sdcard]\npath: ~/sdcard" >> $KIAUH_CFG fi + if [ "$PAUSE_RESUME" = "false" ] && [[ ! $(grep '^\[pause_resume]$' $KIAUH_CFG) ]]; then + echo -e "\n[pause_resume]" >> $KIAUH_CFG + fi + if [ "$DISPLAY_STATUS" = "false" ] && [[ ! $(grep '^\[display_status]$' $KIAUH_CFG) ]]; then + echo -e "\n[display_status]" >> $KIAUH_CFG + fi + #Klipper webui related config options + if [ "$WEBUI_MACROS" = "false" ] && [ "$ADD_WEBUI_MACROS" = "true" ] && [[ ! $(grep '^\[include webui_macros.cfg]$' $KIAUH_CFG) ]]; then + echo -e "\n[include webui_macros.cfg]" >> $KIAUH_CFG + fi + #G-Code Shell Command extension related config options + if [ "$ADD_SHELL_CMD_MACRO" = "true" ] && [[ ! $(grep '^\[gcode_shell_command hello_world]$' $KIAUH_CFG) ]]; then + cat <<-EOF >> $KIAUH_CFG + [gcode_shell_command hello_world] + command: echo hello world + timeout: 2. + verbose: True + [gcode_macro HELLO_WORLD] + gcode: + RUN_SHELL_COMMAND CMD=hello_world +EOF + fi + #including the kiauh.cfg into printer.cfg if not already done + if [ ! "$(grep '^\[include kiauh\.cfg\]$' $PRINTER_CFG)" ]; then + status_msg "Writing [include kiauh.cfg] to printer.cfg ..." + sed -i '1 i ##### AUTOCREATED BY KIAUH #####\n[include kiauh.cfg]\n################################' $PRINTER_CFG + fi + ok_msg "Done!" } init_ini(){ diff --git a/scripts/install_moonraker.sh b/scripts/install_moonraker.sh index 73de3e9..c4eb45a 100755 --- a/scripts/install_moonraker.sh +++ b/scripts/install_moonraker.sh @@ -345,60 +345,6 @@ setup_printer_config_moonraker(){ fi } -sc_check(){ - SC="#*# <---------------------- SAVE_CONFIG ---------------------->" - #check for a SAVE_CONFIG entry - if [[ $(grep "$SC" $PRINTER_CFG) ]]; then - SC_LINE=$(grep -n "$SC" $PRINTER_CFG | cut -d ":" -f1) - PRE_SC_LINE=$(expr $SC_LINE - 1) - SC_ENTRY="true" - else - SC_ENTRY="false" - fi -} - -read_printer_cfg(){ - sc_check - if [ "$1" = "moonraker" ]; then - [ ! "$(grep '^\[virtual_sdcard\]$' $PRINTER_CFG)" ] && VSD="false" - [ ! "$(grep '^\[pause_resume\]$' $PRINTER_CFG)" ] && PAUSE_RESUME="false" - [ ! "$(grep '^\[display_status\]$' $PRINTER_CFG)" ] && DISPLAY_STATUS="false" - elif [ "$1" = "mainsail" ] || [ "$1" = "fluidd" ]; then - [ ! "$(grep '^\[include webui_macros\.cfg\]$' $PRINTER_CFG)" ] && WEBUI_MACROS="false" - fi -} - -write_printer_cfg(){ - #create kiauh.cfg if its needed and doesn't exist - if [ "$VSD" = "false" ] || [ "$PAUSE_RESUME" = "false" ] || [ "$DISPLAY_STATUS" = "false" ] || [ "$WEBUI_MACROS" = "false" ] && [ ! -f ~/klipper_config/kiauh.cfg ]; then - status_msg "Creating kiauh.cfg ..." - echo -e "##### AUTOCREATED BY KIAUH #####" > ~/klipper_config/kiauh.cfg - fi - #write each entry to kiauh.cfg if it doesn't exist - if [ "$VSD" = "false" ] && [[ ! $(grep '^\[virtual_sdcard\]$' ~/klipper_config/kiauh.cfg) ]]; then - echo -e "\n[virtual_sdcard]\npath: ~/sdcard\c" >> ~/klipper_config/kiauh.cfg - fi - if [ "$PAUSE_RESUME" = "false" ] && [[ ! $(grep '^\[pause_resume]$' ~/klipper_config/kiauh.cfg) ]]; then - echo -e "\n[pause_resume]\c" >> ~/klipper_config/kiauh.cfg - fi - if [ "$DISPLAY_STATUS" = "false" ] && [[ ! $(grep '^\[display_status]$' ~/klipper_config/kiauh.cfg) ]]; then - echo -e "\n[display_status]\c" >> ~/klipper_config/kiauh.cfg - fi - if [ "$WEBUI_MACROS" = "false" ] && [ "$ADD_WEBUI_MACROS" = "true" ] && [[ ! $(grep '^\[include webui_macros.cfg]$' ~/klipper_config/kiauh.cfg) ]]; then - echo -e "\n[include webui_macros.cfg]\c" >> ~/klipper_config/kiauh.cfg - fi - #execute writing to printer.cfg - if [ ! "$(grep '^\[include kiauh\.cfg\]$' $PRINTER_CFG)" ]; then - status_msg "Writing [include kiauh.cfg] to printer.cfg ..." - [ "$SC_ENTRY" = "false" ] && echo -e "\n\n[include kiauh.cfg]\c" >> $PRINTER_CFG - if [ "$SC_ENTRY" = "true" ]; then - PRE_SC_LINE="$(expr $SC_LINE - 1)a" - sed -i "$PRE_SC_LINE [include kiauh.cfg]" $PRINTER_CFG - fi - fi - ok_msg "Done!" -} - setup_moonraker_conf(){ if [ "$MOONRAKER_CONF_FOUND" = "false" ]; then status_msg "Creating moonraker.conf ..." From 8ba6aee952d7c3a3c0c96c090d4d908a320c156d Mon Sep 17 00:00:00 2001 From: th33xitus Date: Thu, 29 Oct 2020 23:32:24 +0100 Subject: [PATCH 6/8] fix: add fluidd to ui message --- scripts/network_functions.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/network_functions.sh b/scripts/network_functions.sh index aa5812b..2b7c7e9 100755 --- a/scripts/network_functions.sh +++ b/scripts/network_functions.sh @@ -96,9 +96,9 @@ create_custom_hostname(){ echo -e "| You can change the hostname of this machine to use |" echo -e "| that name to open the Interface in your browser. |" echo -e "| |" - echo -e "| Example: If you set the hostname to 'my-printer' |" - echo -e "| you can open DWC2/Mainsail/Octoprint by |" - echo -e "| browsing to: http://my-printer.local |" + echo -e "| E.g.: If you set the hostname to 'my-printer' you |" + echo -e "| can open DWC2/Mainsail/Fluidd/Octoprint by |" + echo -e "| browsing to: http://my-printer.local |" bottom_border while true; do read -p "${cyan}###### Do you want to change the hostname? (y/N):${default} " yn From efe482ea589d3765072228e715eec7dd2655f24a Mon Sep 17 00:00:00 2001 From: th33xitus Date: Fri, 30 Oct 2020 00:10:40 +0100 Subject: [PATCH 7/8] fix: upload new image --- resources/screenshots/main.png | Bin 26752 -> 26723 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/resources/screenshots/main.png b/resources/screenshots/main.png index ac71eb72f6c3fbfc122d1f3ad46da34131b9125a..8de3a1fde428fa6ffece94f3c3f94c93735c69cb 100644 GIT binary patch literal 26723 zcmb5W1yogCzdd{a3F+<>X#wf(Qo50D>5^`c5@|^V4&B{IcT0Dtbf@IE4?fR(?;Zd9 z)nG6D~|)_?_JNow6JVcoPaXxWbR`vI1b=C@x8zkd}bjU`p257saikA(!9^6%C6O>1vM z8vI&Dur~8>!`_rg7 z^#SC7ZG?4!lZU52tq#4mRL=<nXRYQ(z#Aw`&dndM zg-%J1DIya%-6BuOe0@WXpYHA0=hB{QAb#|Sl&J4_O*7GHM@`6o@tkRsYV`itcm1xh zbwel;m(y)$i30K_Btul@5oQart0q3%AFkUwLZ@YWcX9gOy+Wxf7rvqbdrDCrlUbyf z`E|C#?Ic`=iZ)?ZTFo341-ADQIa;Lsct*J}26$YM11w=A2z>o+Pd__^Ly)$ z>15+M&@6bbpDES{qdAiQsRyUEG{dKddpxGrdy=VGUxPB9gDrxy6Y*sdS*9;c9RF2a zLl29{@642X;K25(5MQ0ilk2C$b>By3`HvXD3pc4S7ufJ4w+OOx$R6MyACLGR|E#dP z05w5BQ~ufMtLp=`{NQ`yOHC~9yRR)qbL`KYxXK#<>0b9S_9vpJ`$tq?g<|npG_A*{ z2O<5Fk*DNklINB<9i8YWK6O2{J=HzEAK>MO?%g8I@Cx3!qCFMa! z`pW$7<}Cc|o$!92E3U*PZ6AnPMeeJdG^E()}@lHwg&NTk2* zua4~=;{hH?REqgTl>2%#s11Zxmi!+;8na&rp_yOTQLGiHm)WTh`&$d7nztuCZLf4^ zorz8uPKu(EeZJ;a{kXver4CXze95gz=&`rw#^zF$ioC|#Q##&S)CWTeyz#sx!+RQk zx*eeucwDOeG76jHJQvH$kj=Drvx3fhY@w@OI;UNJG17@uCnla+yT(s@9FUGD zYM7rOXyC=?o%bhKj5ie507W5v_Ly7%HKV+BLwv=_R6Q;62O&Vp!`ReBmt%an8wGsu zWB!RYAY_K^vi9r|Xn4_Uh8MunJM~boIk^~M+~1UQVhPAIW6$YNn%T}F;%|~KsEfbG zBjm?MG&MHSg;ThgHs7~6IxSn{ix+y zx$~I*dmdkFn3GchsvH4Ud(1hl2+YT7OLI!5yd!dWvYF|dTOnXUAm~_pM`xAK3KW_^ zjvF5~h~J{~Q1NBkzZSts`?ZH@%6a0R*X}5V@IHu?RJ1lcd}7^pcQASu?_iW=mMqYk z;Nk?ml7szZu7N~LHM}v0dE7f-X`B+;X_g@nQcG)cD6;XWjLu)OFXyzlb0i=;^Njh) zJ=u-!z5Y$>j~Nf$L$Zx@ zy z#KBZ8T@;4LESsbwXz5e53Wtui5?^UDVk?-63=Cx}Us8_@GE|u9P_x+Vf~~t*=I?c; z5~RT)D<>f?^&~WYZrIN^_k(VqdOIVT6u4GjwNw ziL}SbYPcAA?zu^P7i#;$F}%)wzwT_`VA!GMHhF_EvXSwc;|%|z9O00@q=x45#x+hV z?7~TtK{vXzwq|;Z;336XEt~mcqJSLNB_GCAyGyt9<=0OaH_CW5q~jx=RSSZ;flRa| zg9B4@blxngc)Po2<`3h7+Gk0zuYv7u8aynte$VuYWJvJH=k$U}#+QoX|`hTX6C^%#pMDC0N=< zgeC0OO3+?r{80DqLEV$&4acxq%mrC} z6|E5wFBnc@VoS4oD~^m`%^@lW>MO`~cGYViA3I@v>PU!ZQBlz|b$PnCd)7tNG_RrI zBmGPDJ1=`_lWq?~rspG~wt0`LD57FuMq7|>XC~@CB24gf*kv{tfbIlY;XuABd9Qw# ztyq=?Z1w!%zsH|Hw|VN1yz@A+3WOU8K2!m?M9^=qqhUEu{5k9%)V)dgXSjWBda2mm^k7lEYOf6Hh>2OsoJBU-zI%fPs}FyE#!b7gKZWTaJuU2-k-3{_SWFmm z!o5c<6%Nxtdo&kl)&>w{)TPc4a6N@}}TBlOW;c_>F=(;N0n2m9rJP z_2f@z_j6y%Acw6SmpJVZffH;|4+y&CopP*>^>`IYqPU@n9guT;9fK1!ViqxEN5rlRzA;sS*wM#qpV4Dc^DybD!QIiCR(?N<^WMqZ<9x}RnBTb7fU=-!zb>iYpA!8r?T0Gb<+Dou!qm~wDv_k z+dRv*^VEK4rnJ{_gxSN8w;<{F%V~xxjb4e!WRjo1&!hSz_bv@9^#|x?re1B>wA_~5 z@FuyYFvn_geLG}#(Pea7wAe7-IJSzT=^xK*KbJO1-5mkYMDxbC4xik&jH%C9l$ssD zbig5f`Br8>e)K1Q_te$_3g`9|Wg!1j{p$lW-~b$wd29B=wk@a%VXofc{p`r*n7wou zB=g^_qUI-%U!Kq6zo#ptKnVVWJcUDhK6C#vrqNaR2mtT_I2C0fw(qJnn)dZmF2Fzl zHlbukbg4&CW?$!&fh4_ON#m^kPIvOOmBMLxqM=wPHRs<{R+oA!w!38$s~DwB^a|T| zY43GawGwNlO-r0a6#peO-5$VN2@9dotrY$D*|p`R`H3PeHe!%yMw3B6h^7_<3e0)@ zQ~CcmfO7z$9)V46*?Af9NGv8N zFHpSBpgRA6`URh9;UK50y)}&CIi|?^#3O3a7%ui=RDfs(P@jQ891NSnoUQC%VmWy= z>ZP~`Zy;4vq-9pljvOLjF|Bj*aQ|Cv>oixhuGNghkiQwP++BN6z~A*qcXyrQTwwq9 zBBTeFvG#s#FO3x-p-C%b*-jgLpUT+zO)8q5R|YR4{2#iNf1T~oJoH9k#&G&g(iHin ztA`;o+Vh)%I(=FC{x*k$AtB_y^DZS7Ev19Vt4;9$^D{lI@qp5W69zt74ghlfr%+DS z5jArj;a{vQhMY)A2c($uYD2S`&)r_xkGa60(!{5dR}FWR-9I+^JQRwwBlPDB^b8e0 z{&qXW@zy)cA4bw5NRK8Ww`z`8q=Qc zxEDw76!O?ARp|cPSTtPzzBtQ1$e~)>%U`S^AsEB{Jdv~)`qoKAVIqL-;TdSCWX?l zFjuH_g*-hIO|oqr?S!!6=#mg%g^dJ@D_OrH&~ZllB&YpKa|Jje*hIfdE$kr)oQW2BjKk zTA8iV(NpJ^R+Vb`n`QWq@bTR^<^_h-TzB#=obq1`@1yB$KF^inNd0R#M(q(DB2l>eyAMAr*y^swHi0*VQ;b&3QMT#4;Y5JB89tVv(X#x5oko z2OO;3D6aO;zOb!5yxoXumdJKGR>OG6mJy92e6Xeg5{icor=6z0mCf*sYBvL+FRpu@ z6VKp06Ns;902b*T=O((b?&htrmxQ$@)=8n5;O~uB^G8J4ObP3TDaW&bfBm%qc0yGV z$fFJ`w6>bQMbTP%iviTPX(&WI#XFM&!k6v;;mZ;i;8=yU(clPI%(h1+)-{1gLKVal zMVr+OjP3+}cIlfvnDVGzl%Ss*3Zm5`a$cpJqb~{Td9I=G`wq&=NHnjJc>)#ls216w zoj$_}rcI9?KG>#SZajSTXwn~Bbr*3(!)Ds+E0DhUXg=ex^WKCa`g-r}FUXGlvU&Tp z_;s!Su@CmsH=)`w8@*h7259%0fYhW?-f}YEi=)Gd+Kt0fs6aU{nI3oeMDq~gqYtGO zK27>cQP)L@1N*Wvcr<-&z0L*xsD2}S!b(#P`B_Azm4!;Ti~u?Qvg}yV8YX)`LUv8T z+DPMO3@s!CyCV$s_EZvt;8*PF57R3=Q?_<%Z1S$@VN@%0?A+-P9Z2;S0tTCiyYFy- zLMpC{%p}pmMoY)FJe8w->z2OZ090N3=dwvmLw-%|l2ihvfbO(3-V64?BAXItO;28- zTV1cF%1_Rmr*}<>qY74eMVO{Tr>Ouux6+N95^ zr8oVsN7d(a7ledHo#aY_4RjDjGYwUJrvm8viO;8lh=zrGt|o%R8wWDzD~#pzuOXl^ z%t)@i=9{}Itj;%#qI%qO0$6?>`cR|#w4>om({l*t-73(X?)etqb_F zcvOP`o2P*Lu5>rHGG}H7KUx6JLV@`m6!JNIFWyyPmYz|@Dl()!721H@71LQ%y`g-c zlbK1h76FiN+$H$q-ZY&u8SpZ05~uHLoS1Iowic+H$X@6{2ZdcT=8>tufIc?EVhPuM zY%deMUNC}5bG21EVYi_p+`F}kE{(&9;6PdWn!9`u9 z*T~~208-Guo25X;a>@buJg0!aUy+u*DlA`)P9C<`W3NXu#cP{@jriMsO^qm`c)2Um1UYLzWZ|m zmE>vkqdVXu0)AsMdxd3|j{{tac6l-4{ivUA>xXe9juS66qme{b;z=pv#LwDZmf$Sq zP-8NBpG^v)R7*@I)umvJo~_iCjlPPsb>xv5)ZGlVIw-aM{UAex){hbsI9_~9)HA4B zk^bc$Gpeht^8CjaPX*5-2i-4T^Dliirk|vb0gDb?F49VvwzVCFBB^m@(BoPPf}BGt z`p;u2@j(W&+&-0>>%^!`K2o`VIIa*(qaByg6ud*B4-!IC_T0agIxO9X>W}!y;M0*T zrsTTEm)fg&;QzFHYP1U^TSIl_>xy=ls&1s zBNSM*S)3`ZF^->91|IyGIuZ1-|7*!Ns>yi0*|LN(7q(RJ)DpE+7%A-Bu}h5E;U2)5 zh+x#gZ3+ftOO9i@;CNZ&Tu0lQ5-u(WYBtl@bqlz2mKoC zsz*AhWZH)Jsx7rYgaPJ2_4)_0pE{Fr)80`qH1Ib87G+kxOEzCnzMELb$afK=481Zz zehYFB`?K|v%*hqe?`4XcS=&#Z&86>;xcEX{4}49_+lC{w`D^T_AGsfwJ;LtL%YO+V z7*O6ZuDD5oujE+c*%fMMFQxw~}__U}^XuTUx z=yalZb_xQ$it6Zw8oKqwwtawQYdyQ^><49ZB#z6iF!P>%#mRHC`zfoR70mhg^s9(C74Nk|CS5lwjj0|Tj+Qd4K7 z8k^Z}5UH{)pz7;{7JGzy%(otHD=&~AI<)8)e~ebL2LZkLrj1XvdWr%eX_NaAIdM*B z?U#*cEE`6+M+DZLeufJAk;bLHWqq$0;Gz!dUWFBZILb)5KA`2${+;#7G_Lza^=UK9 z(c#VX0d#Pv(Be*#I~T$Ax!o6;|ArwK{jR1m~xJN}UtNn`q+{BXT4r$i$px zsW&vfuiBa!fjkuU3b9h7?v*u1O3vj;0Sb8tjGAyuo=V!c94f@}OT)PJ5v7M$ZjaXJ z6g7EHY2UviMh!4&y_T_x4vHyGQwJx!5+Lew6ez*;n5dK$SJuee8J=PmZG1_!^`3Fv zk$YaqDBJdvkxM`H*oj5B9-kvve>Vr4y9(`lPEcZ84%Ij-;zU_{!3JfE%f!3E!XF$= zctow8#!R=V#4T{1C`5#~6UQutTufwBBTABEH@=+&(gm6_7IW`jl_7yk4o%({<^#f3 zuKKc!IfFKysS9@z-D&gTmNVzD(~r293C>}m8+dspM!&|11YI;28g_p7vJM0fC`qI$ z^#3M&r-zr=C!58;;C&Xf^kG}}mtH}8KyOZuGN~cL{;mw#=xRo>kNP0qbd6)PSzWffB^J9Z06Tp*#LQgOfD%`{fb&sI ze2a>#3M#-P&0l-5(@&+9aGR({xfl5KA(lc1kTX zxs@=dcyYIeF`-dP7&@RR?a6c(w{iBehpLx3sPgi)o?$- z-euJqqnaKs0J~hBJ@rc(ngUraA#oHLTWDzru;rXov{y62J9`)Rwbp@rE^|qHU@~IokyYrqRNP>Fw%rY#x}$ua$FCBQqhMo>dJURY-{dIT>gHryWww!O3}=n zej2Y)nfo>TooT_+#pqX%%9>m*_V7h>71E|oqeH)qZCtz3Scue+N+eYsVTfDw*A*{v zLvs&Tc6lAeFGHFgZGU%*xEz=>6O_yio>p8AbW43O7hBQX5~){mr%R4zvNh{EW#Prt z{uzqG5C4GYU8eZuZY1(DL;wR*LV&iYEKOA1qg+k74iaJHxx=^XHrg`P4XV6~#>0fo zxozkskXg&~a1BJ#_UyY}$X9%K5tI5xU@isXHzAy{>N~2E){Q@`LW%gWsxI5SG^x`6*D>>uQgz9 zC_=aKOGN5c>B6N$?Nl;dv?qB(e)&Z8Co9v$6qs;&KQYfNk*oM=RxT!o$r1>^OaPH$ z^@g#P`H4Sca;y^B+D^JQKwMdQ=X0L3yY;z#MwRGJQ<0Nq(Zw&moV-CTs|Clq-kSLF z?&=`1ZCd7idfjQQ#Q1RujlJUNhV+Zg4Vrn|C{mUB`J?O5$?p1;OzcyKZ{Czn%kjL- z8@$rYw}&6nx=gR;8M22P!L{*xO`+!Zx*|Y)TR=Caa%^X{3CH9jIUgLwZP%n=+x|NP z8xj62frvi~$+l7JYk%?+bp*ohucNF!1A^uFrdI6+;+0dcohlwK=A#eS8K2*!a4I`#r~C1o(1=9^1fqP0OwlJhrNG%WB>or{X5~ z;=LF#r(;%G7rE0FE450g1kMB`jRFBQja}|ULOn*?5!d~AjqbD*CU@_wmLX4t!vQv^(*tSCV+8XuL%vAiggi2W;pskR zITakE-kCU_zKk{V5)qm|ZfGY-G}B%wM6*?RZMy51sEdYQD>i7--rFOTjINiW$RE(l z`Uc6HdJkD!Ra_Ys@Y(CFUj_PS#h20Io5tptMl;^8vPYgQC{~V=`oNApR`<}Mt*tj3 zr|ZtO$D6JV%(tg~v}lKa`Xs)bioUn;bw2M1muvhpob9kT2#!_e!z3gC#oa;lV&?^A zM~ni*{n32@h=b(Wfkj$h^j1SQw8ft?TF@xQhXUaQ|9}p7`89;U&`R77!GW+m2R{Ho z_H97}Zbn)SQ3NPDT{n99DE)ao?f@J7x7P4vq%nz)Cl$d=$VqslXFzC47h4;Z_2ksM zi?omWmYIQCLy+M`r6@8#2_T7B(2cepUD7jSZZYdG6AR#VGyd6Tcw0(%L#od#!KEdZ zze;xxeC+>_-IS-OPKu~3>72-P(14PCaXuQCMpVObjN1F)RJd*4yIn%=$xCXzMG>_% zO!OWI8DJw;RdaI73{I3{8(WNKWt$1TJoE@)ji;&ka>rW0Jg&S#^HJ?3;}UnXz%ZuD zvOV>j(H2T&Yc=68skZbj-LHl;dT?sABsgw8&|{9$t}_?fy@CqDP+ zm=Tv1U%MR4jg94oz9p{qXvorI#5k->xeyev?R^e#z>Vx##FbYWXHI??)y34wB!KQY zdW3V%i@5D3a7o^-km~b0)Is*l2t=CtWKaao%l|B`($3HK9-j`XFwa7d3Q67KwIyAB zciwLv`uLqY>27#y_>y?JYeg8mlmXkvMA4gVY7fr$_CCmYw#KePO6?E2 z_@H|QHE~WoKXUVQB@&Ju=ocXQbs@WrR+TqG?3j*LB8t$F9D7$RuL)O~*dW0d0G;z( zS7o{qrL6)nS;PTHjq+SYVwm`(@xlduG)M{*uvw1(H`9!Dm~xUyZHMBKZwXQM&$NzA z){_w(5n|Z^CX4k|g%wEA)y<(_S;SAWKk#Q&K&oD`!h=z0I9n)MBvc?rNcsR+G+zxEZexdr;6zlzCWzjgibOf9glA_1I_ zTpaUI-y$<-0sgE`szaCcDF;a{Z88Cr_zV3lv6p?8u`~eKC))C8$q~Q|MxmV{+9*{T4i2OHE88v2pVwYAU`$jBQs9(3)Hr8SzR@V1 zMu+1{(^4R4vNW$+Iw6~%u{)a=kx?LCbsCJ_xy^9ee3p%S%9AoF)NzT~dmX&r6sXtw zFfg_LzV!PHt%3j(5PLG+KZ<2O=%Lps`A9%l#O_Ax2)K+O&aj}$e&Afi?WA0*A#N*c z(^+dl4W5`kS{k2m;f1>kuOSY25CM>!vAZD>8mD5Vtww#0yQgj za0-Cz2pDcK)oo&4c)b%Uy_@v}n#W1T#QzQ$mj4nl!Pro{?hLcO!0LjaSx!Qt%jv?( zg4a!5xyd65IaIH+wlV`u8Znrf;;nznkoqzqmOB${wan6fk=hYx z5Om)(CDqg;Vs`^4fFiyHX_>cKxJNV4a}=u?XyU%v$DZ2$(!L}l*{s(a@_@4YTaxYw z4Jlr$Pf4^k?Ll|;3gc=Pi^x8?wHT!0vAfx@3GIPl0O z6_buc)JjiUgHgxE>5Jtkib~pi)`3F514@~_7bH%fQGJTv*?Dg&O%_?O&3Ob!wW%>q z$^~grUD4k79ag935(=Pr6$klw_XI(|)TI1qBv$*N%f$5a^nX(vJ8@o5hy0^B68OAO zRbc$^@#U1{rjmIafIpx%c1-rPO?({(V}F&qW!CAVDZg{0Un`MDLX0L=6%y@~(;$;A?>G1sQOgUtXv*D?rt z_#wv36S??!nYMm;*!#WP!Bxzdo<;sQp%hk+lUMj@Vi`}*SkomDJO8bofKQ>|nFq2L zsgMzKUo>-1jncHlrUWUh>2VBNbp+JS?5GbyqTb`U-_UHx9kB?*Im}v|d%GfoQTHR)n z8RGFuQ1d4vEZ@iL)T6~XjI<3Dq)&j|zbBQ7OdW4|RvyRCy(CJRtAmlh&l*(I=Ldm0 zv{Z9V+vy{0o0-;jaZ_5jN}yrkFL8QAV;Dsa+Fzu{L5J%eTnnkxxAv}9Ejt5JtfZHK zhNYt9yfa7HvH|fS=g5ZDg5P0yc$Op`q4C>t&vnr$x%{s|KhT7iP>$#vBPg?5;;Q#J zJ1T6fe-lfcPnXSX(MY`owUs;Eo4~M!1ca@`SolN;h!Sk3Tz9JIXM!3{U*&m#Gp%&E zeAj2HRxl-{;kkg#Ifp?fo>cP4O6a8d56(=o zjxLd+FZW*@%w`<>0uS?1wskjC7UMqorVqaD#p@2XQN}+83!dLN2$0nnZWaF$qq*$9 z*)C|z$+LDMv`Ig*_}O)IT+o_Y#hg23H}CM1Ziiu!zuH$tY;+GEufAGU?d|LO&iLaXF*2?x#_LR2RDzPj!bry+t*2Hn*+`22a z+OMp2cF0c)YbYM968dX71OABT>?19JWaL5cf9j6g0$-Cum?AIs$}uvpDo)Sj`d3jA z-!sRxfnSn0rBUL45N>$MRX?4-FsNbbI|J&VW(sg%{_ZVHhDMM)+VNlmlXg!VDMh+~ zkeo<4Q_|M21dN)`(nucHs!xphAMu|NF6rHI7*-x&(Ls z^$-8zCK<|!7)l)`I_81nCR&YRqOHZphF@niXL8PAB z*`YUr@%0N&>U2R^gmh5SELK~twJ07ZGnN_w_?5mJ@gYg)QDXHE2lf)5YYLaaDFjKq50I^_SN+dgCj zOloORee7=2HV5y}7<>KnD-?eW{$y)CE$3NW7kpvuh&GXi_b;_*I%Om)nG6dn%=qNN zbELZtmu@m1?>Hwu`)RdJDhH~m*sqMLXUy~^F1D6D$v`tn=!$#J2JOyj#^weTNSrh% z3?}LFns)IP>7&oqX-F)TXb^Kwa*NWb%OT3nDl?8I=S<#8Pczqp-w`)yuUEjEw|Qd| z?Gb-yY~707Fs!@c66|rboY^>CeiMtZdSIOkl{oG(w6xFlc3!(XdGix&Af$5n3jZtd~^PL{-FaRH9el=Tfp z^1z)zC(mBERpX`WfgXrUtl<+ykY6;@UsaM>$_|K*Afc7Y?)~9bXrhWtpwUIM9BL)) zmTxQVbc79zwigIuBid1*3FmiXN~SR2zFC#@rde83olEyX71C^7uE43P?#oZLg;uOb z%CxGet_mPwyNX_1rVRAgo0Z!zMltl#z3i1@XgG>BcGPPQ+M8=_xu#iU#wC#o)lYac zDcV+wX2(_4$NfXMb<_ItSIcE6Yml5RR9BEP%FItZaboOEc4PE~zh`4PbpD>k4T96RNPe8)LSJc3QZ z&5g6Og5TY5n&mGU=KI>3Xfw$@of$gRJ2e6CIH2uwE5dGi@?O$uYGs17$t39>o1B{v zz$`Khg6i~uC>UnSu{Nfu74Qa`SyN%lf^NKui+^Ty6xGSx`2YlR z@Xe{yHve9ntvnxV)YKY6lqsMg{|nJDVS0aX9Fy|Ek_~ z_j98p#vS!ZR>V|Q)jgHPl6OXt4(zTE!FOs!bl1)9uZL*~pX|8B=s2wC7>V9*I=5HV zq`rBNEbd!;Rl!~J@kY_Xw5b?Ze}#TF5#M#%3d^jfvh|NL7J+z11NiqT@{ z<_K{q4bb-B!gvw~Pk1aZjdPVI!#C#C5!=!T1J1Fn^TEMFTNtW+m!LUxCHMD4AunaV zsE0O_?BT$1K0~te?Be-Xno0@E_U?%LpFELs{SwHY0hx(zFcyS-sE_>T=1G+j!n+Y7 zEq&nL1%USkkx4=2N_Hjm$)%T`Eug)!0aBS4FQ^OZ>3+dxYhmjjJyEN{VDw6zQ z=aT%(q7UXg#cK8*1dJ&oA9RsTEe_Lk(tWy^fcKnL&VkT?s5G`}$6zKuPj?pj-@xvY z_EauH-NS=@kL7lupKXT16-`S2IfDg>Z2McR-Td#8}5VL{lHq}{@AGpUXVM(*6N%_2Co-1&8q zu1d8^LNLQ6kO1feFU&CGhZ^+YbBYXxwVJ*1wJamea(WJ0dn&HVro*O1Xdk zKxDoQ7?B{=BDw#qE=J2{zItXWRY z5bT=mq8twJmo#PE<{s#!)-GJ?TyFf%SmciboPPE0J033!^Bls%Kkrs6=URZVVC0Lq zY9>XOpzeQgRQvBfLi{y4a2tBGcWz^~2r0xl@viVe7-iG5EbA+`X~Fy^MJ14lb5=Q< zPFJEAF8eZ1fiRjM&0+LYPB1`d`6MjN>s&aR=N8H#{$1N8Tn*E%ttX21f=3`z@ z@MIJ)n(jWFpGd%~@=)a!jcBsV>6Xvu;E}~u`PYDiktmYMRHXVuYB){>KR#FxhpIet zugcGvrg{bYIq@BC?gU|&#f0%re=f@rvaeK!CAx*n<}3;-$@?!h{(@HbHQ z)84^C{jO&kI6Y^jX2ozKq!!RB{Ef)g#8u&!D6b51Yk2C#*_>91W!}yD=@TH`=-EID zjZW-7m$!KNvTW*^+>r9G9ohUW;6&XojnQJ&ub?n|`>SkO2m1GD=fxXdLiB#vL{* zw3HKBX<1$oqJU?Z*xjBDsRNvgH2Sl)yO?@|Q1?J+;l`LH1=m%EZ0~ow?Ji@k12CKB zp!I+Rf8!T85?fR@#MEyL&Fe1eHQH<;8$rM}oo0;$=7}MAnGv`^2F$+B|LhFUchdg# z=T-d)(uHh37X6)7Xa-{KXLfq(#HO_%XLFc(Y1I9 zNZ_FFV@&8Hm-AqkT()DtM3EiH?_p&*%T`eNxT48Bar@e)Rw-7U9+j#0F4`jxa8O z=kB(}s!GvVj09Dx8(fR@K^KWs@%CKd;QkMRLLJ}e-aLjAF9I*gVkyAD#J7EFwj&{? zU2AGX6db_CqNZp;pCnIG@<{sWRI>TE-n}qj$M~##Gz#-d_Q2$gK!o}d++_OV59pz) z*c&eBQp*fmz;OVvya3`z9_*zmL-OxshbVs5)opzpAJ~-fSAk8?wgDh0=oca|5i)p% zTj@vd*`+Id+h-$k)w@V#JN^7`><)})K$E(oRW6w*9)K72QWp#Avog$7yQe^59xfA> zl^1M|3Pirj!un!4Ft7irFc#xBKPjizU0~kk<|pwmq9(g-?vR7Y`N=X_+i;hpuEyH^ zAPQk>w$vuNeC~B!s5%cg(L&#N`@HiTX$Z{hL+iwbmUz45;C<-8l%;3C&R@8 zXP_49mm28mW=+G6s>K{l;S}eDlYrcW>6o%I8`zv2^IM-t8V}1HNLb5%UE5c6_C)fs z8$KOO9TLW0DI~ShEVKyo@d}+3JmAFd*GJCSkeg+4uuIgVo}CPY*!w($&O57W1dW|z z)LoOqXAz~~>}B?tXXb?PM$j9tm<;nA0c_Mj+raC#q-@&z?F&EXRdnTXFx zUOz_MF&Wry@puXE?!j-89XlkjDUE#3&q8|QCFrbb`$^v1ESw9ua(gZ?UCwo(^RwFCk|o7@jN^2#0> zMzPr<|J_J!6vbGQm510r)Cf~#SV7GG9H+(Iud2h9z3z{b3$MA?Rn~dTuTF1Y(Dtgp zB3T&ISz<3d+gbJNfVk_lHtyy-0)o|e=9Qj^efcsBCH}~VeIkURMi(V`wWkqr;fMWT zkwM_rVbDE@h6=ZroA>kglor-VdlPDvaTwJRZ_qg`E|Nxu8ke!L+4KgTe8}};e5o@Q zEOTq8?K});Y-hhB=!7TtYm0F~3A{5u;@Ur6f4%vz|tMh#s25Gibs% zt91jDN2E+Qv))j@nTqTa7C!>%K~i@z&T|h!wUy1vSlFGEM4%H8Kg2{04(8PwC+Gn~ z;o~K^=v8JbLF>saQ*_!4cpe&b{SJ0zkvKWC(hhT)z-6Ha@`z+{k4k!djIV6kHXn1CnTk7%~_$2y{ZP*sxuS}veQvUh=jR@MTtN`Z)+BC zfr64a5s-qySlxGc=cXlgZK}3)b-?zLj;hOwWt6%` z!y{C1dekz$sQ;Trh<(O1r!5tK%_;})F>odAIv{7n?tihGo=XOp)r`pSY*1tU>o>JC zWsnN~$8TEd;@J9NJh|`eHS0^IF_C@6Deds2l|LyO$$Q2P1a)TI1qeXlOMeoN(_B+p zYwy~}x3A&!ivgRaMt!L>S=sf@-8>)hB-#o52oVZ+isCdwueW3tUP#Nck7D?mLG5lr{t8a)V2z=yj};$CyMog55Z(0-h-yg zj7QOs=JHePFCjF`o;^Zo3vMp~vV%cDreJWiIt$nFn`hX&jhpviPPv8mn)QfUp3$Nmhx-g}N7-_S%^5fFTRC!+i1o{>v(i6z z{nyzRWctn)d-PKL-<-e7>1nR4sB>|{XF?z0I(BaDyV>ccD(F?1lG2OvAK8#PfF(HV zuIC(R_|nvum448Im%o#HLnjU;5r2Y9N7S8>DrWruZa7srw(1tKj;7CSy8{sK)I1j1 zDn5lJ8J_(s;3`0{U&Y-EtfDh~P9VxpG)5iJgCQ?IfKp`JiQujJ25I__KqRr}#U&D% z6@>vA+R9|t%SdE$YdzFugMfd{r#SS2fa5nueq%0QKgF=l9d)oU9ha~?HLQZD_JUn2 z5~YhpCSDq4fS<@BEHF>oUN%Up8$gQbtLcJ-Y#bV%FWp&6G2(uQBK^2-(6{&c5}Rc% zCfC_>8f#;f+S%TH+{fO!KF|=1$kxYm9Fo@}4&^c^E>EYUtx;e3Kdq*E-KHP}&jyWp z`Uq=H()<7acGKJg$w;yt);FgTr$fouJ-sTWxPEZiSJl&CoeS5&cTR7%z7}|l%MeS| zYvtTadT3c4T718^xmdH;USFXR!cq!BdvZ}0ki5uTDO@v_NJ1t6+rn=yVxo^EGuieXv z2OILwRrWN|CkB&p5^tMn%{{Yi3Y@>s!#gB5^B*fM@;i~HIc_eUj1BKiG_b ze?x*oZf*3AF=yDZE-~5^2#`+y{J+{e>$s-=zwZwbhO{EmAfkxU-65%fgrG<_C=F7h zC7ejtkQya|bm!=95F`aQLb|)}GxYnte&65ky6)?7|9}5A*f@KfjqP*Z=M~Rm(&E6M zBUo^1+9rqjV8~xHTkLJ(3zt_|R5OFv;W?9qwKvox@FHZUSqU?u=tSNdAFbP9<4hj$ zIqLs6ithY40qt?)dknf{KHdkCw9VKl8*U5_8cg3gY60m|Y>*Rwd+*~5Pg|`V^Q{m^ zpWjAhfef2HaH`;)Ms+gQ{1vO6oGa+g8+LjHV#55>G8T%W+q-&)lRRRy0HvU*jHrRn ze&Ca_=e&a|zviJRVInn>=xc5MsF!}we*{b+zgY5)Fz~3H@>G@UkUx0$?12hG+g`$_ z`ssvEBB6TXYt>`d5wqwUIiZLklJ^)8^SSj z(;E>Xg>htmpt~UOctIXNVgVE{$Fi8oUbJlUlla-V4QV+Iuk)nmz0aydM^12VjH(Hg z0Da+UE|-=R%8X&*zau9W0(|$f;LT8s#U?*ynJ9$LF%Ss5PfRFiy7wLvvep-IWep~Y=hl}>v(H?3}=b>h0La(x1Eb1Yls@eBnEr$G4C+B@&T1* zqz2+yRe=-Rr%LlZ>}l=}>Msir4nervWZaIU3V|r<~_wTFmQJ4lM2_sRvvNL7G~Y9p5Qy2+R0k zx(}k}o{08ZxYs3nAHsA;%Gs)qi-L<& z9n@79)rzaIBS%{wa1Al_J12V>@{b4(4k2Lo zt6$mRM`FEijoHzC9I<~Qp8z{tIS@TPVc!8Br8jXW_%Ee(vXTJTy*vr8|6Ou>rGm-J zw|S{QJ``NYmlNMmw%#e@&+uxZnb?aRPY#+s#g$43f|Z5%y85Hl7CF6N5etG}8h1<4 zahG99OeIU#g_(BZk;hb}PYio5*sM-*-23g{ zJgl;J2B~0cJovkhLsoy)$FZZM0ZJYaHA*+CmCpNqj1s>?FcpuZ7R&3cTaLQpDRUBD z43^_*d-eyO&cTfRdpMn=q>9ANXcv;+rT~^iQqnC-s_}#6efRQhhM*f^?If<^A3D-f zx|njB(p_R#*5Bi8bB@`EK^LlrN)|(rKo8=h@)*Ce~d$NO(*ajZtn= zyJuZd+%q3!sI}8?VPFhS?mZ2b$mPEnS%30L;NWg3>lQhN678uF@du7jrP)=W6GDhO zMJ=@oFCKkn&u4>()|@+#A{-Z5cneZrb~)A0p0FyiZ^-?J5uQ%K{=fU+(;cw*dtpYG zt`TF?Y7n_%CRab>$;VYiZ+C8!fs3AGe{7;{7a)KyG6G`e_28*Y_-oQ|z*8npgTxhf z{Z+A9++e<%aujQxDW@-tNl*)`e;ZEe;Z`i0`T~75C3}=*&1>~f+Z;dZz5-!@=x0#$ z3%}QQiohhehlk{$wsGzrJSy?R7Z0l8E(wc3wZ|eAW0Il@9&nW+0-}wMQyTHOzs5TY zIZI$CtOGHB{B4%xmFvIk?6!rudJBNbC$$ORq3;y+ja}7eiYr15cNB(s>YLF5%z_p zfBSXbLSX1k23Wvqwg_w-U+gyMq|i!5!>RT@^~E5C;*Xa0hY5_EX`UN%?>rEF$HJfY zskx-iW1nD4oDLDt`gT+VlgqXlJ&P(`&L>(6W*7^YL-uE|k-rS!rY z$;SNPE6gMUjSaRUqTjHkI+~YLL+p&n0;$&+;S?UbB^dCra!K}Jill9?D_=NK%+jc#64r{QqPom#+@i$%dEB2%HrOu)5~#xwSsYM2Tul z(ua96$quC(8yhul7hSmVU1jCS6FNOdPGmHVhPZ_J=S0MjzYqj>Nm@@>n*VQu7X(_B znGyrmkjJ^%pAP7-xz7ovquTjEbjoI%f2V!z@EgQ8YYAjI@e5bCbTH`e>nNjoup@2G z$J`nrRtP43n-WLVx8>!$LEIr#7ReXv@j~R}Dw1s&ec#CK*wSQ30vu7g0)SnVsK-zo zU2Ans<>R!%Y`{^Et0G{KuThcW1ryz+Gza3oEVV@yzNg&=9``qCR&(?(u@EWqmSOPvJQy{`Q{oumFzg*rczH8L}ahSsOsO1*j6S-8hbW?zZ{0B4wS>y>k(|(#cVlEuLYw+fQG_F2=96uNAFY3jK&hy z$P=H>hc18FVtDm{TNVILzilmIv0WP-NSoQJ8vW>K5>5`^rxid6ZNB)OU27gNRMpP`7W!6N6P87~FVVI}~_s zzimQ4OWs)s+7$ac>c~zFG}a}b(%n%0VVI8Ho$Em9YCVq{2N$Lq9P_j1B$r@iNs;)S z{a~}u5X(+_uurR-EHbZ+JZNt=h{eBh+RThV61K@A#e7_YmwGzlE;e><`vjoE%Srd) zUbz)fSjDD_ct>NsmqZ{iaH6~I&*Un%qBjaUzeIzNvz)T8>tv+SnEG*n{)-3TFi_Yuj;^3hAj0u;9%ZgfjV)i&x*}9?QoNwVt64b>NL}jg> z4>)7YS;2uPhMa@_H0t#_jn&n%d3Y%~_oi}~UnkSSawjq6?I}oqBrSZEJU`zYvjzl| z@b}hrbbR5n4F;#?1vaBurQS_vqT>fx6NAU^mDdZhblRN|Hkg7Wd9&4rlKsuhbWO+m z4=qMjbxCFW<$g~4Q3u<2OxHQvn<$O<(umv5EU@N*{a`of@r;a=?|$MTW$UxLo2z+# zzV3ThB3+f{;u&IV;n~^Zx_cpyRA*rH!lEX^RrRlJk zk~W@{QBx=3sFN@U9A3N?mdnzNs1s2VbS+SNSTaG^B+frrqU*bBEZ{^{)44P$I5{cq z`1kNcdcBONu0mCuW1HUF@4Hkyc)?|CDeYi^o010f$8DR<4VRf?4E0)f{4ja*@|?-d z^o&oT2=6jyroek^pC-|d+Ii;M64qi}ZvzPFT^~5{p3t`slahbAJ#i|uFJ&F{|7^HT z!-WQ8*s5XNGGPE#Kns@Tq4c%Q!NrRlUyPloHIF|2t> z*aHOkZ!Z%$uu6$FJ0y*|vUFt6Z&(HXHs5{?2=*9lYJjHDP3a*3turnwt~3)8RT_W~ zLIqj%Z{40Mw=MhLXj+5U?g0+;o~y(AtUcZbj?VXzxY(vO7bMwF3>2!~DyUD{D|8Jl zXZm-eO{WA%F>+CmT7 z^WOW^UgYiRx2+M;X{vE9uDW0cYCxw4#-err4;nZ*ll9em5NZwN`@LACfDj1|rrg7v z4&xiZyhkoa{#XeJ^&-9FIk8Ar0}j~-QS7KkSPNCmx~q)1dS1|}Qm_>xG%6K@ zBrXR1lxsH@U5v?^f=X)@5xEjxR}8VFgghBsUSXBcZX6$gtb#S9t2gYrAV6e~9%w30 zBP&_K*dD=?!Vz$0m}{Jjr>yEy8r4F=e7TJ>PC;vX0M3Djkw0CE)=JbEeXO z^ET6On_eHgY_3_FKD_23_Lzarl+*B=vo!WS2k;iI=0_`9o540sLXcOhp1ixCt+js# zaw!b0B$d&W?D-}XY|ZVWegSzt$#Edh7qSUVFT?BCOq9*F8XU?&FU5jioI#8+K}&`= zCthk>kyw0f&VNm>0hunP9tr z!knX9lj~HK`;uNbH@Vl6{X!|WTZ_TnxVSGTpL4sC#{QPaAzC+AD)re00_-*(ezn1>Pf1KYjUDP@_h6i zbke3As9gXz05|S4ObG{Ke?2y{kPV!}1c*WC{@@)g5ezbY1~h8Q1TT3jD_&SfBA8eb z=FfSx)ju(1e;76B4gY2O_}88=T9CT;lt^n;ef$33^sg(tTPIs{T<@{vY6KfA$(( zK<*&d>@d2?)eXOU#n!Uo6&xnAuB5Wu1EwX@H#MNfD48oVn`R;*WpaVasu_~{4n2Qa zJOwBY{{Yg2L$7uO#F09f8MJ*4r~Q)xFYs%u6TOdvWgkv0eLEQ)W2H;c>q*}}Mg@in zvlB6$3+5;RWlDN#rq>sM!-nCHkO!9K`4|e}l>vW(fG!|aVu=+%y`m;6Ky;K%(dDM}r*Q0!<`^S)m>8{$#G=5+UYr$U# z8d%^$q^>NWV!8)Bp9OJuHI;P_EJz7ZfPkeDei2=M3k?sG)Z>9rFM>+z(>eE!F~!O- z=BJ+@lsnd?j$;M)OlFF1NYkoRSNl3S1$#tFM;szsojvN7-Y|){>mF-EZq^P6*$!S|0`T{~U$%z#K z9NisSBYBzkBIH#9-RPSvzb++{a4U2tR^`%Zshjb|5H<4jEvv5~rI!dRFpJ*88>(02b%Ad<^T@b@Z5|lQ?xZn1iQscHcM-=GU{_N?SX8ak?e5KiMbcR zlGX%(Zc)G&ydV*Y;_g}H3#ZVv79`pnxIQszOdGXN8w+G@iO}A9Lvy{V`)KP_ebf^n zA|~B)(1_rAl$#DZ>neq#iASR@o=MJU8D<}62i&L0i4KtgUz3p%Kc>%DG)xoAROrg4yQ_nBc zWFY=I>HBV#t~akph0$b)6pPYpsHL>8e&WEHUHY6AwdEm9SIaeWylxv9M;l~E8&9eFsx&x#^oMrB(3bC|ZPVPsO9MY#}x09(> zD};*kn^G~Ex?2cB65*sDeJvWL2{g={+(XDij=z?Yqrr(L&)UA0PF%4AnRBjX_~_II z6h9nSyE+8X`hjraFl?GsPgFZ5FHrq!=|S@lKQ zGfEP+9_7p#(d=Yu!7|nTyY8acC@T!g#jf1 zy@HBPan7lweP+s>*?4dY&AA4;nXcEG4(qh{`EF`7fZ|nw-dJGlpIIv7u2>>n zMx!+YxZdp!+yJQhcC;dE#czpzjQNmzBU{n5gJ~+>YqGQ>MUCO4CHMu6_Q2cZtaFn> za?s_TTgqWw)HE<2Fp~2zm_E;aSAFvbw`=h`YIfmPWL(9io14_4LsQw{re#Lydas7u zRYy}2LKqjH5fej82((op;^9YVAR@1a0`?s=5RtG45S?G}ZQ&+(q9F!!II>>{K#48h z({0{iimB%SEc+)Kb1*ptCT4N{`H~^rMI7nUE^DTh45y~|BVO5g#85)ES-OehwJF3>nMvHol(|BQ=WqtsYvV<1G)9$<;9;?K;k+$aN#VIOOL`5oY?J< zKI^KvDB9N_k={>&)^v62EbgPv4&IL{Vl#8z_yYwHH0Hx?KwB9T4c>b2RKm>R} z;cd9s1#FZIojJOx*!f+aU(f3&)W_bR|3+q2mfg9+Xxm7~|Vw}F8L#)32 z1AXm+a_01lD7H_JS(8K>0JJwb;f0;MXHuj*TiWIcZN~Z1=33-=1r8d6*(}lKyakT6 z1Xk_hRF znx{)36b@FZbe(bda4o}qF+&@$)csmdY*jIjiUafK?vjZ0*`W_BBb^48HzeVBHmvB1 zZ|}c}SbxSyJ~UL-gu&oG1(1&CZTgMRwG#b(VEVVoldA8M?y}{DQko50I&c-92aYnY z9Zd`!O@)jdOo1B^7Y7#yD<=mlm!LWqmk=+v5H~L~2Zs;`N2X?o(myt^wl#Tc2Kk>i V7`e{718e|#CZi;sFKOWWe*g=ODi#0$ literal 26752 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

s2=X?+XH;G1NF!d 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 KL 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 hCjRmUYg=OrQ`dig11e%nA9%y5`*JFGvt^%p|39 Date: Fri, 30 Oct 2020 00:11:20 +0100 Subject: [PATCH 8/8] Update README.md, changelog.md, features.md --- README.md | 50 +++++++++++++++++++++++------------------------ docs/changelog.md | 27 ++++++++++++++++--------- docs/features.md | 50 +++++++++++++++++++++++++++-------------------- 3 files changed, 71 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index 41d262e..78f013f 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# KIAUH - Klipper Installation And Update Helper +# **KIAUH - Klipper Installation And Update Helper** -![main_menu](https://github.com/th33xitus/kiauh/blob/master/resources/screenshots/main.png) +![main_menu](resources/screenshots/main.png) --- -## 📢 Disclaimer: Usage of this script happens at your own risk! +## **📢 Disclaimer: Usage of this script happens at your own risk!** This script acts as a helping hand for you to get set up in a fast and comfortable way.\ **This does not mean, it will relieve you of using your brain.exe! 🧠**\ @@ -12,7 +12,7 @@ Feel free to give it a try. If you have suggestions or encounter any problems, p --- -## 🛠️ Instructions: +## **🛠️ Instructions:** For downloading this script it is best to have git already installed.\ If you haven't, please run `sudo apt-get install git -y` to install git first.\ @@ -28,7 +28,7 @@ chmod +x kiauh.sh scripts/* ./kiauh.sh ``` -### Additional Instructions: +## Additional Instructions: If you need some more detailed instructions on how to install Klipper and Mainsail with KIAUH, check out this website:\ [Installing Klipper and Mainsail](https://3dp.tumbleweedlabs.com/firmware/klipper-firmware/installing-klipper-and-mainsail-on-your-raspberry-pi)\ @@ -37,9 +37,9 @@ Feel free to check out his work. --- -## 🧰 Functions and Features: +## **🧰 Functions and Features:** -### Core Functions: +### **Core Functions:** - **Installing** of the Klipper Firmware to your Raspberry Pi or other Linux Distribution which makes use of init.d. - **Installing** of several different web interfaces such as Duet Web Control, Mainsail, Fluidd or OctoPrint including their dependencies. @@ -48,85 +48,83 @@ Feel free to check out his work. - **Removing** of all the listed installations above. - **Backup** of all the listed installations above. -**What also is possible:** +### **Also possible:** - Build the Klipper Firmware - Flash the MCU - Read ID of the currently connected printer (only one at the time) - Write necessary entries to your printer.cfg, some of them customizable right in the CLI. +- and more ... -For a list of additional features and their descriptions please see: -[Feature List](https://github.com/th33xitus/kiauh/blob/master/docs/features.md) +### **For a list of additional features please see: [Feature List](docs/features.md)** --- -## 📝 Notes: +## **📝 Notes:** -- Important changes to the script will be listed in the [Changelog](https://github.com/th33xitus/kiauh/blob/master/docs/changelog.md) -- Tested only on Raspbian Buster Lite -- During the use of this script you will be asked for your sudo password. There are several functions involved which need sudo privileges. -- Prevent simultaneous use of DWC2 and OctoPrint if possible. There have been reports that DWC2 does strange things while the OctoPrint service is running while using the DWC2 webinterface. The script disables an existing OctoPrint service when installing DWC2. However, the service can also be reactivated with the script! -- If you used Mainsail v0.0.12 before and you want to upgrade to v0.1.0 or later, you have to reinstall Moonraker as well! Mainsail v0.1.0 will not work with the old Moonraker service. Don't worry, the script can handle the proper removal of the old version. +- ### **Important changes to the script will be listed in the [Changelog](docs/changelog.md)** +- Tested **only** on Raspberry Pi OS Lite (Debian Buster) +- During the use of this script you might be asked for your sudo password. There are several functions involved which need sudo privileges. --- -## 🛈 Sources & Further Information +## **🛈 Sources & Further Information** For more information or instructions, please check out the appropriate repositories listed below: --- -**⛵Klipper** by [KevinOConnor](https://github.com/KevinOConnor) : +### **⛵Klipper** by [KevinOConnor](https://github.com/KevinOConnor) : https://github.com/KevinOConnor/klipper --- -**⛵Klipper S-Curve fork** by [dmbutyugin](https://github.com/dmbutyugin) : +### **⛵Klipper S-Curve fork** by [dmbutyugin](https://github.com/dmbutyugin) : https://github.com/dmbutyugin/klipper/tree/scurve-smoothing \ https://github.com/dmbutyugin/klipper/tree/scurve-shaping --- -**🌙Moonraker** by [Arksine](https://github.com/Arksine) : +### **🌙Moonraker** by [Arksine](https://github.com/Arksine) : https://github.com/Arksine/moonraker --- -**💨Mainsail Webinterface** by [meteyou](https://github.com/meteyou) : +### **💨Mainsail Webinterface** by [meteyou](https://github.com/meteyou) : https://github.com/meteyou/mainsail --- -**🌊Fluidd Webinterface** by [cadriel](https://github.com/cadriel) : +### **🌊Fluidd Webinterface** by [cadriel](https://github.com/cadriel) : https://github.com/cadriel/fluidd --- -**🕸️Duet Web Control** by [Duet3D](https://github.com/Duet3D) : +### **🕸️Duet Web Control** by [Duet3D](https://github.com/Duet3D) : https://github.com/Duet3D/DuetWebControl --- -**🕸️DWC2-for-Klipper-Socket** by [Stephan3](https://github.com/Stephan3) : +### **🕸️DWC2-for-Klipper-Socket** by [Stephan3](https://github.com/Stephan3) : https://github.com/Stephan3/dwc2-for-klipper-socket --- -**🐙OctoPrint Webinterface** by [OctoPrint](https://github.com/OctoPrint) : +### **🐙OctoPrint Webinterface** by [OctoPrint](https://github.com/OctoPrint) : https://octoprint.org \ https://github.com/OctoPrint/OctoPrint --- -## ❓ FAQ +## **❓ FAQ** **_Q: Can i use this script to install multiple instancec of Klipper on the same Pi? (Multisession?)_** diff --git a/docs/changelog.md b/docs/changelog.md index bad301c..ffed9a3 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,25 +2,34 @@ This document covers possible important changes to KIAUH. +### 2020-10-30: + +* The user can now choose to install Klipper as a systemd service. + +* The Shell Command extension and `shell_command.py` got renamed to G-Code Shell Command extension and `gcode_shell_command.py`. In case the [pending PR](https://github.com/KevinOConnor/klipper/pull/2173) will be merged in the future, this was an early attempt to dodge possible incompatibilities. The [G-Code Shell Command docs](gcode_shell_command.md) has been updated accordingly. + +* The way how KIAUH interacts and writes to the users printer.cfg got changed. Usually KIAUH wrote everything directly into the printer.cfg. The way it will work from now on is, that a new file called `kiauh.cfg` will be created if there is something that needs to be written to the printer.cfg and everything gets written to `kiauh.cfg` instead. The only thing which then gets written to the users printer.cfg is `[include kiauh.cfg]`. This line will be located at the very top of the existing printer.cfg with a little comment as a note. The user can then decide to either keep the `kiauh.cfg` or take its content, places it into the printer.cfg directly and remove the `[include kiauh.cfg]`. + +* The `mainsail_macros.cfg` got renamed to `webui_macros.cfg`. Since Mainsail and Fluidd both use the same kind of pause, cancel and resume macros, a more generic name was chosen for the file containing the example macros one can choose to install when installing those webinterfaces. + ### 2020-10-10: -Support for changing the Klipper branch to the moonraker-dev branch from @Arksine has been dropped. Support for Moonraker has been merged into Klipper mainline a long time ago. +* Support for changing the Klipper branch to the moonraker-dev branch from @Arksine has been dropped. Support for Moonraker has been merged into Klipper mainline a long time ago. -A new function is available from the main menu. You can now upload your log files to http://paste.c-net.org/ to share them for debugging purposes. +* A new function is available from the main menu. You can now upload your log files to http://paste.c-net.org/ to share them for debugging purposes. ### 2020-10-06: -Fluidd, a new Klipper interface got added to the list of available installers. At the same time some installation routines have changed or have seen some rework. Changes were made to the installation of NGINX configurations. A method was introduced to change the listen port of a webinterface configuration if there is already another webinterface listening on the default port (80).\ -At the moment, the Moonraker installer no longer asks you whether you want to install a web interface too. For now you therefore have to install them with their respective installers. Please report any bugs or issues you encounter. +* Fluidd, a new Klipper interface got added to the list of available installers. At the same time some installation routines have changed or have seen some rework. Changes were made to the installation of NGINX configurations. A method was introduced to change the listen port of a webinterface configuration if there is already another webinterface listening on the default port (80). + +* At the moment, the Moonraker installer no longer asks you whether you want to install a web interface too. For now you therefore have to install them with their respective installers. Please report any bugs or issues you encounter. ### 2020-09-17: -The dev-2.0 branch will be abandoned as of today. If you did a checkout to that branch in the past, you have to checkout back to master to receive updates. +* The dev-2.0 branch will be abandoned as of today. If you did a checkout to that branch in the past, you have to checkout back to master to receive updates. ### 2020-09-12: -The old [dwc2-for-klipper](https://github.com/Stephan3/dwc2-for-klipper) won't be supported anymore! - -The is a new, fully rewritten project available: [dwc2-for-klipper-socket](https://github.com/Stephan3/dwc2-for-klipper-socket). - +* The old [dwc2-for-klipper](https://github.com/Stephan3/dwc2-for-klipper) won't be supported anymore!\ +The is a new, fully rewritten project available: [dwc2-for-klipper-socket](https://github.com/Stephan3/dwc2-for-klipper-socket).\ The installer of this script also got rewritten to make use of that new project. You will not be able to install or remove the old [dwc2-for-klipper](https://github.com/Stephan3/dwc2-for-klipper) with KIAUH anymore if you updated KIAUH to the newest version. diff --git a/docs/features.md b/docs/features.md index 3ba46c1..c8571c1 100644 --- a/docs/features.md +++ b/docs/features.md @@ -1,25 +1,33 @@ # Feature List: -- Automatic dependency check: - - If packages are missing but needed for the asked task, the script will automatically install them -- Switch between Klipper Forks: - - [origin/master](https://github.com/KevinOConnor/klipper/tree/master) or [scurve-shaping](https://github.com/dmbutyugin/klipper/tree/scurve-shaping) or [scurve-smoothing](https://github.com/dmbutyugin/klipper/tree/scurve-smoothing) or [moonraker](https://github.com/Arksine/klipper/tree/dev-moonraker-testing) - - The update function of the script will always update the currently selected/active fork! -- Toggle auto-create backups before updating: - - When enabled, a backup of the installation you want to update is made prior updating -- Preconfigure OctoPrint: - - When installing OctoPrint, a config is created which preconfigures your installation to be used with Klipper - - adding the restart/shutdown commands for OctoPrint - - adding the serial port `/tmp/printer` - - set the behavior to "Cancel any ongoing prints but stay connected to the printer" -- Enable/Disable OctoPrint Service: - - Usefull when using DWC2/Mainsail and OctoPrint at the same time to prevent them interfering with each other -- Set up reverse proxy for DWC2, Mainsail and OctoPrint and changing the hostname: +- **Automatic dependency check:**\ +If packages are missing but needed for the asked task, the script will automatically install them +- **Switch between different Klipper Forks:**\ +[origin/master](https://github.com/KevinOConnor/klipper/tree/master) or [scurve-shaping](https://github.com/dmbutyugin/klipper/tree/scurve-shaping) or [scurve-smoothing](https://github.com/dmbutyugin/klipper/tree/scurve-smoothing)\ +The update function of the script will always update the currently selected/active fork! +- **Toggle auto-create backups before updating:**\ +When enabled, a backup of the installation you want to update is made prior updating +- **Rollback:**\ +When updating Klipper, KIAUH saves the current commit hash to a local ini-file. In case of an unsuccesfull update you can use this function to quickly revert back to the commit with the hash you updated from. +- **Preconfigure OctoPrint:**\ +When installing OctoPrint, a config is created which preconfigures your installation to be used with Klipper.\ +That means: + - adding the restart/shutdown commands for OctoPrint + - adding the serial port `/tmp/printer` + - set the behavior to "Cancel any ongoing prints but stay connected to the printer" +- **Enable/Disable OctoPrint Service:**\ +Usefull when using DWC2/Mainsail/Fluidd and OctoPrint at the same time to prevent them interfering with each other +- **Set up reverse proxy for DWC2, Mainsail, Fluidd and OctoPrint and changing the hostname:** + - The script can install and configure Nginx for the selected webinterface + - It also allows you to make your webinterface reachable over an URL like `.local` via avahi + - Example: If you name the host "my-printer", type `my-printer.local` in your webbrowser to open the installed webinterface + - If there is more than one webinterface installed, you have to append the port to that adress - - The script can install and configure Nginx for the selected webinterface. This will allow you to make your webinterface reachable over an URL like `.local` - - Example: If you name the host "mainsail" and set up a reverse proxy, type `mainsail.local` in your webbrowser to open the Mainsail webinterface +- **Installing a G-Code Shell Command extension:**\ +For further information about that extension please see the [G-Code Shell Command Extension Doc](gcode_shell_command.md) -- Installing the Shell Command extension. Please see: [Shell Command Extension](https://github.com/th33xitus/kiauh/blob/work-13092020/docs/shell_command.md) - - - to be continued... +- **Uploading logfiles:**\ +You can directly upload logfiles like klippy.log, moonraker.log and dwc2.log from the KIAUH main menu for providing them for troubleshooting purposes. + + +to be continued...