#!/bin/bash # TODO: Add Crowsnest Support # TODO: Avoid duplicate printer names # TODO: Dry run # TODO: Printer Directory Page in NGINX # TODO: Fix PolicyKit issues "klippy_uds_address" # Handle arguments ARG_HELP=0 ARG_SKIP_APT=0 ARG_NAME=0 ARG_CONFIG=0 ARG_PORT=0 while [[ "$#" -gt 0 ]]; do case $1 in -h|--help) ARG_HELP=1 ;; -a|--skip-apt) ARG_SKIP_APT=1 ;; -n|--name) ARG_NAME="$2" ; shift ;; -c|--config) ARG_CONFIG="$2" ; shift ;; -p|--port) ARG_PORT="$2" ; shift ;; *) echo "Unknown Parameter"; exit 3 ;; esac shift done # Prepare global variables SOURCE=${BASH_SOURCE[0]} while [ -L "$SOURCE" ]; do TARGET=$(readlink "$SOURCE") if [[ $TARGET == /* ]]; then SOURCE=$TARGET else DIR=$( dirname "$SOURCE" ) SOURCE=$DIR/$TARGET fi done RDIR=$( dirname "$SOURCE" ) ROOT_DIR=$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd ) cd $ROOT_DIR source ./ColorEchoForShell/dist/ColorEcho.bash if [[ "$ARG_HELP" == 1 ]]; then echo.Cyan "HacDC Printewr Setup Script Usage" echo.Yellow "./setup.sh [options]" echo "" echo.BoldPurple "Option Description" echo.Rainbow "-h/--help Display this help msg" echo.Rainbow "-a/--skip-apt Skip installing apt packages" echo.Rainbow "-n/--name Specify printer name (skips popup)" echo.Rainbow "-c/--config Specify printer config (skips popup)" echo.Rainbow "-p/--port Specify printer port (skips popup)" exit 0 fi # Pull Klipper git submodule update --init --recursive # Install packages if [[ "$ARG_SKIP_APT" == 1 ]]; then echo.ICyan "Apt packagees skipped" else echo.Cyan "Installing required packageas" for PACKAGE in `cat $ROOT_DIR/config/apt-packages`; do sudo apt install -y $PACKAGE done fi # Name Printer PRINTER_NAME="" if [[ "$ARG_NAME" == 0 ]]; then NAME_NOT_VALID=true while $NAME_NOT_VALID ; do PRINTER_NAME=$(dialog --backtitle 'drwho@hackers.town' --inputbox 'Name This Printer' 8 40 "${PRINTER_NAME}" 3>&1 1>&2 2>&3) if [[ $PRINTER_NAME =~ ^[a-zA-Z0-9_-]+$ ]]; then NAME_NOT_VALID=false fi done else echo.ICyan "Using passed printer name: $ARG_NAME" PRINTER_NAME="$ARG_NAME" fi cp -r $ROOT_DIR/dirs $ROOT_DIR/$PRINTER_NAME # Select Klipper Config cd $ROOT_DIR/$PRINTER_NAME/klipper make menuconfig CONFIG_FILE="" if [[ "$ARG_CONFIG" == 0 ]]; then CONFIG_FILES=(`ls config`) CONFIG_FILES+=("Enter_Manually") let i=0 C=() for f in ${CONFIG_FILES[@]}; do C+=($i $f) let i+=1 done CONFIG_INDEX=$(dialog --backtitle "drwho@hackers.town" --title "Printer Selection" --menu "Select Printer Config" --output-fd 1 40 0 1 ${C[@]}) CONFIG_FILE=${CONFIG_FILES[$CONFIG_INDEX]} if [[ $CONFIG_FILE == "Enter_Manually" ]]; then MANUAL_FILE="" while [ ! -f "${MANUAL_FILE}" ]; do MANUAL_FILE=$(dialog --backtitle "drwho@hackers.town" --title "Manual Config Selection" --inputbox "Enter Full Config File Path" 8 40 "${MANUAL_FILE}" 3>&1 1>&2 2>&3) done CONFIG_FILE=$MANUAL_FILE else # TODO: maybe replace this with the full path? CONFIG_FILE="./config/$CONFIG_FILE" fi else echo.ICyan "Using passed config file" CONFIG_FILE="$ARG_CONFIG" fi # Select Serial Device DEVICE="" if [[ "$ARG_PORT" == 0 ]]; then DEVICES=(`ls /dev/serial/by-id/`) DEVICES+=("Enter_Manually") let i=0 C=() for f in ${DEVICES[@]}; do C+=($i $f) let i+=1 done DEVICE_INDEX=$(dialog --backtitle "drwho@hackers.town" --title "USB Device Selection" --menu "Select USB Device" --output-fd 1 40 0 1 ${C[@]}) DEVICE=${DEVICES[$DEVICE_INDEX]} if [[ $DEVICE == "Enter_Manually" ]]; then MANUAL_FILE="" while [ ! -f "${MANUAL_FILE}" ]; do MANUAL_FILE=$(dialog --backtitle "drwho@hackers.town" --title "Manual Device Selection" --inputbox "Enter Full Device File Path" 8 40 "${MANUAL_FILE}" 3>&1 1>&2 2>&3) done DEVICE="/dev/serial/by-id/$MANUAL_FILE" fi else echo.ICyan "Using passed serial port" DEVICE="$ARG_PORT" fi # Build Klipper echo.Cyan "Compile Klipper Firmware" cp $CONFIG_FILE $ROOT_DIR/$PRINTER_NAME/klipper/printer.cfg sed -i -e "s/^serial: .\+$/LINEHERE/g" "$ROOT_DIR/$PRINTER_NAME/klipper/printer.cfg" cat $ROOT_DIR/$PRINTER_NAME/klipper/printer.cfg | replace "LINEHERE" "serial: $DEVICE" > $ROOT_DIR/$PRINTER_NAME/klipper/tmp.cfg rm $ROOT_DIR/$PRINTER_NAME/klipper/printer.cfg mv $ROOT_DIR/$PRINTER_NAME/klipper/tmp.cfg $ROOT_DIR/$PRINTER_NAME/klipper/printer.cfg make -j$(nproc) # Flash Firmware echo.Cyan "Flash Device" make flash FLASH_DEVICE=$DEVICE # Copy over printer config file echo.Cyan "Setup printer.cfg" cd $ROOT_DIR/$PRINTER_NAME cat $ROOT_DIR/config/macros.gcode >> printer.cfg.tmp cat klipper/printer.cfg >> printer.cfg.tmp mv printer.cfg.tmp printer_data/config/printer.cfg # Apply Edits to Configs echo.Cyan "Setup Moonraker" cd $ROOT_DIR/$PRINTER_NAME/printer_data/config sed -i -e "s/PRINTERNAME/$PRINTER_NAME/g" "moonraker.conf" sed -i -e "s/pi/$USER/g" "moonraker.conf" cat "moonraker.conf" | replace "~/" "$HOME/" > m.tmp rm moonraker.conf mv m.tmp moonraker.conf NUM_OF_PRIOR_INSTALLS=`ls /etc/systemd/system/*-klipper.service | wc -l` NEW_PORT=$((NUM_OF_PRIOR_INSTALLS + 7125)) echo.ICyan "Using port ${NEW_PORT} for Moonraker" sed -i -e "s/PORT/$NEW_PORT/g" "moonraker.conf" echo.Cyan "Setup Mainsail Config" cd $ROOT_DIR/$PRINTER_NAME/mainsail-config cat "client.cfg" | replace "~/printer_data" "$HOME/$PRINTER_NAME/printer_data" > tmp.client.cfg rm client.cfg mv tmp.client.cfg client.cfg sed -i -e "s/pi/$USER/g" "client.cfg" # Download Mainsail cd $ROOT_DIR echo.Cyan "Downloading Mainsail" wget -q -O mainsail.zip https://github.com/mainsail-crew/mainsail/releases/latest/download/mainsail.zip unzip -o mainsail.zip -d $PRINTER_NAME/mainsail rm mainsail.zip echo.ICyan "Installing base nginx configs" if [ ! -f /etc/nginx/conf.d/upstreams.conf ]; then sudo cp $ROOT_DIR/config/nginx/upstreams.conf /etc/nginx/conf.d/upstreams.conf sudo chown root:root /etc/nginx/conf.d/upstreams.conf else echo.ICyan "upstreams.conf already exists" fi if [ ! -f /etc/nginx/sites-available/site.conf ]; then sudo cp $ROOT_DIR/config/nginx/site.conf /etc/nginx/sites-available/site.conf sudo chown root:root /etc/nginx/sites-available/site.conf else echo.ICyan "site.conf already exists" fi if [ ! -f /etc/nginx/conf.d/common_vars.conf ]; then sudo cp $ROOT_DIR/config/nginx/common_vars.conf /etc/nginx/conf.d/common_vars.conf sudo chown root:root /etc/nginx/conf.d/common_vars.conf else echo.ICyan "common_vars.conf already exists" fi if [ ! -d /etc/nginx/mainsail/sites ]; then sudo mkdir -p /etc/nginx/mainsail/sites fi if [ ! -d /etc/nginx/mainsail/upstream ]; then sudo mkdir -p /etc/nginx/mainsail/upstream fi if [ ! -d /etc/nginx/mainsail/proxy ]; then sudo mkdir -p /etc/nginx/mainsail/proxy fi echo.Cyan "Generate and Install $PRINTER_NAME nginx configs" cat $ROOT_DIR/config/nginx/mainsail-upstream.conf | replace "PRINTERNAMELC" "${PRINTER_NAME,,}" | replace "PORT" "$NEW_PORT" > $ROOT_DIR/$PRINTER_NAME/upstream.conf PROXY_PORT=$((NEW_PORT - 7000 + 8000)) cat $ROOT_DIR/config/nginx/mainsail-site.conf | replace "PRINTERNAMELC" "${PRINTER_NAME,,}" | replace "/home/pi" "$HOME" | replace "PRINTERNAME" "$PRINTER_NAME" | replace "PORT" "$PROXY_PORT" > $ROOT_DIR/$PRINTER_NAME/site.conf cat $ROOT_DIR/config/nginx/mainsail-proxy.conf | replace "PRINTERNAMELC" "${PRINTER_NAME,,}" | replace "PORT" "$PROXY_PORT" > $ROOT_DIR/$PRINTER_NAME/proxy.conf # add proxy sudo cp $ROOT_DIR/$PRINTER_NAME/upstream.conf /etc/nginx/mainsail/upstream/$PRINTER_NAME.conf sudo cp $ROOT_DIR/$PRINTER_NAME/site.conf /etc/nginx/sites-available/$PRINTER_NAME.conf sudo cp $ROOT_DIR/$PRINTER_NAME/proxy.conf /etc/nginx/mainsail/proxy/$PRINTER_NAME.conf sudo ln -s /etc/nginx/sites-available/$PRINTER_NAME.conf /etc/nginx/sites-enabled/$PRINTER_NAME.conf sudo chown -R root:root /etc/nginx/mainsail if [ -f /etc/nginx/sites-enabled/site.conf ]; then echo.ICyan "Restart nginx if the site is already enabled" sudo systemctl stop nginx fi # Setup klipper python env echo.Cyan "Setup Klipper Python Virtual Environment" cd $ROOT_DIR/$PRINTER_NAME /usr/bin/virtualenv klippy-env $ROOT_DIR/$PRINTER_NAME/klippy-env/bin/pip install -r $ROOT_DIR/$PRINTER_NAME/klipper/scripts/klippy-requirements.txt touch $ROOT_DIR/$PRINTER_NAME/printer_data/comms/klippy.sock # Setup moonraker python env echo.Cyan "Setup Moonraker Python Virtual Environment" cd $ROOT_DIR/$PRINTER_NAME /usr/bin/virtualenv moonraker-env $ROOT_DIR/$PRINTER_NAME/moonraker-env/bin/pip install -r $ROOT_DIR/$PRINTER_NAME/moonraker/scripts/moonraker-requirements.txt # Configure Systemd Environment Files echo.Cyan "Config Systemd Envs" cd $ROOT_DIR/$PRINTER_NAME/printer_data/systemd for ENV in *.env; do cat "$ENV" | replace "/home/pi" "$HOME" | replace "PRINTERNAME" "$PRINTER_NAME" | replace "PRINTERDATA" "$PRINTER_NAME"> "$ENV.tmp" rm "$ENV" mv "$ENV.tmp" "$ENV" done # Copy To Final Location echo.Cyan "Run Copy" mkdir -p $HOME/$PRINTER_NAME cp -r $ROOT_DIR/$PRINTER_NAME/* $HOME/$PRINTER_NAME # Create Empty dirs dirs=(logs gcodes certs backup) for d in ${dirs[@]}; do D="$HOME/$PRINTER_NAME/printer_data/$d" echo.ICyan "make $D" mkdir -p $D done touch $HOME/$PRINTER_NAME/printer_data/logs/klippy.log # Configure System Services cd $ROOT_DIR/config/services SERVICES=() for f in *.service; do echo.Cyan "Setup ${f}" SERVICES+=($f) cp "${f}" "${ROOT_DIR}/${PRINTER_NAME}/${PRINTER_NAME}-${f}" sed -i -e "s/PRINTERNAME/$PRINTER_NAME/g" "${ROOT_DIR}/${PRINTER_NAME}/${PRINTER_NAME}-${f}" sed -i -e "s/pi/$USER/g" "${ROOT_DIR}/${PRINTER_NAME}/${PRINTER_NAME}-${f}" done # Install System Services echo.Cyan "Install Services" sudo cp $ROOT_DIR/$PRINTER_NAME/*.service /etc/systemd/system/ sudo systemctl daemon-reload for svc in ${SERVICES[@]}; do sudo systemctl enable $PRINTER_NAME-$svc sudo systemctl start $PRINTER_NAME-$svc done # Cleanup $HOME/$PRINTER_NAME/moonraker/scripts/set-policykit-rules.sh -z ln -s $HOME/$PRINTER_NAME/mainsail-config/client.cfg $HOME/$PRINTER_NAME/printer_data/config/mainsail.cfg sudo systemctl restart $PRINTER_NAME-klipper.service sudo systemctl restart $PRINTER_NAME-moonraker.service echo.BoldCyan "${PRINTER_NAME} is setup with moonraker on port ${NEW_PORT}" sudo nginx -t if [ ! -f /etc/nginx/sites-enabled/site.conf ]; then echo.Red "NGINX config not enabled, don't forget to symlink the site.conf file from sites-available to sites-enabled" else sudo systemctl start nginx fi