diff --git a/.gitignore b/.gitignore index 049fbe2..6804318 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ user_profile.cfg -user_config.cfg \ No newline at end of file +user_config.cfg +logs/* \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index c2dce99..23934bf 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,5 @@ { - "licenser.projectName": "printcfg" -} \ No newline at end of file + "licenser.projectName": "printcfg", + "python.analysis.typeCheckingMode": "basic", + "cSpell.words": ["printcfg"] +} diff --git a/README.md b/README.md index 9d11f59..d4c1ed1 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,18 @@ @@ -20,7 +20,7 @@ @@ -31,6 +31,8 @@ - [Overview](#overview) - [Installation](#installation) - [What the install script does](#what-the-install-script-does) + - [Updating](#updating) + - [Changing Profiles](#changing-profiles) - [Configuration](#configuration) - [Using the suite](#using-the-suite) - [Profile Configuration](#profile-configuration) @@ -69,7 +71,7 @@ ## !!! WARNING: THIS IS STILL A WORK IN PROGRESS !!! - > I am currently running this suite on my personal machine so I consider it to be ready for brave testers to play around with. Expect to encounter issues! But please tell me about them so I can fix them in a later revision! +> I am currently running this suite on my personal machine so I consider it to be ready for brave testers to play around with. Expect to encounter issues! But please tell me about them so I can fix them in a later revision! ## Overview @@ -91,11 +93,15 @@ You can also specify a preset profile for a more printer-specific default config curl https://raw.githubusercontent.com/rootiest/printcfg/master/scripts/install.sh | bash -s -- default +Additionally, you can specify a different branch to install from: + + curl https://raw.githubusercontent.com/rootiest/printcfg/master/scripts/install.sh | bash -s -- default dev + ### What the install script does The install script will begin by checking for dependencies and installing them if they are missing. -It will then clone the repo into your home directory in a folder named `printcfg`. +It will then clone the repo into your home directory in a folder named `printcfg`. Please do not modify the contents of this folder. @@ -103,13 +109,13 @@ The files for the profile you specified will be copied into your main config fol This will consist of two files: `user_profile.cfg` and `user_config.cfg`. -> NOTE: You are free to modify these files as you see fit, but please only modify files that begin with `user_` so that the update system can successfully merge changes. -> +> NOTE: You are free to modify these files as you see fit, but please only modify files that begin with `user_` so that the update system can successfully merge changes. +> > These files will be placed in your main config folder, so they will not be overwritten by future updates. The following line will be added to your `printer.cfg` file: - [include print_config.cfg] + [include user_config.cfg] This tells Klipper to include the printcfg config file. The other files will be included from there. @@ -121,27 +127,25 @@ This adds some moonraker configuration, specifically the `update_manager` for pr After all of these changes are made and verified, the script will restart Klipper and Moonraker. -Future updates will be performed by the `update_manager` service and will typically require a restart of only Klipper. - -Most updates will be performed automatically, but some may require manual intervention. The installer will notify you if this is the case. +## Updating -When the update requires manual intervention, you will be notified of the changes that need to be made to your user_profile.cfg file and the installer will exit. Run the setup.sh script again to verify the changes were made and continue the update. +Updates are handled by moonraker's `update_manager` service. -In most cases this will only require you to add new variables or remove obsolete variables from your user_profile.cfg file. +They will appear in the UI alongside updates for Klipper and Moonraker. -Best efforts will be made to avoid this as much as possible, but future features may require new variables to be added and the process has been made as simple as possible. +The installer can now patch your config files to add new variables or configuration sections. This allows user profiles to be updated without overwriting your existing configuration. -It's important to keep the user_profile.cfg file untouched by the automated update process so that your customizations are not overwritten. +Most updates will happen completely automatically, but some may require manual intervention.If an update requires manual intervention, it will be marked as `MANUAL` in the changelog. -When new features are added, you will likely prefer to customize them to your liking, so it's best not to automatically append potentially unwanted new variables to your profile config. +## Changing Profiles -I'm also open to suggestions for improving this process or PRs that add an interactive update process for profile changes from a patch file. +To change profiles, run the following command: ## Configuration The vast majority of the configuration is done via the `_printcfg` macro in `user_profile.cfg`. -This is the "master" macro that hosts the configuration variables for the entire suite. +This is the "master" macro that hosts the configuration variables for the entire suite. It is here that we configure the behavior of the suite. @@ -161,7 +165,7 @@ Preset profiles are [available](./profiles/) for various common configurations. If you would like to submit a profile, please see the [Submitting A Profile](#submitting-a-profile) section below. - I'd love to have a wide variety of community profiles available for everyone to choose from! +I'd love to have a wide variety of community profiles available for everyone to choose from! Custom configuration can be achieved by editing the `user_profile.cfg` file on your local installation. @@ -231,7 +235,7 @@ This allows all the macros in the suite to be kept apprised of any slicer values It's completely ok if you don't use these settings in your klipper install or even in your slicer! -This suite is built to support ***everything*** so that the user can simply set the configuration values (either manually in the config file or via `SET_GCODE_VARIABLE` commands) +This suite is built to support **_everything_** so that the user can simply set the configuration values (either manually in the config file or via `SET_GCODE_VARIABLE` commands) The idea is that you don't need to worry about the correct way to configure the slicer for your needs or even finding (or creating!) the right macros for your needs. @@ -245,7 +249,7 @@ The bulk of profile configuration occurs in the `user_profile.cfg` file. There a ### Versioning -- `variable_version` +- `variable_version` - Determines when updates require new variables to be added to the profile. It is used by the install script to determine when profiles need updating. ### Default temperatures @@ -265,7 +269,7 @@ The bulk of profile configuration occurs in the `user_profile.cfg` file. There a ## Chamber Variables - `variable_chamber_type` - - Defines the chamber sensor type. This could be 'temperature_sensor', 'temperature_fan', 'heater', or 'none' + - Defines the chamber sensor type. This could be 'temperature_sensor', 'temperature_fan', 'heater', or 'none' - `variable_chamber_name` - Defines the name of the chamber sensor. Typically this will be 'chamber'. - `variable_chamber_temp` @@ -334,7 +338,7 @@ The bulk of profile configuration occurs in the `user_profile.cfg` file. There a - `variable_park_extrude` - Sets the default extrusion amount for parking moves. - `variable_park_base` - - Sets the "native" command for parking. This is typically something like '_TOOLHEAD_PAUSE_PARK_CANCEL' + - Sets the "native" command for parking. This is typically something like '\_TOOLHEAD_PAUSE_PARK_CANCEL' ### Preheat Parking Variables @@ -380,6 +384,7 @@ Setting any of these values to -1 will park at the center of all 3 axes. - Sets the stepper current to be used during homing. ### Homing Macros + - `variable_home_x_macro` - Sets the macro to be used for x-homing. - `variable_home_y_macro` @@ -388,12 +393,14 @@ Setting any of these values to -1 will park at the center of all 3 axes. - Sets the macro to be used for z-homing. ### Pause Macros + - `variable_pause_macro` - Sets the macro to be used for pausing. - `variable_pause_no_park` - Sets the macro to be used for pausing without parking. ### Speed Variables + - `variable_default_speed_factor` - Sets the default speed factor for all moves. - `variable_start_offset` @@ -546,6 +553,7 @@ Setting any of these values to -1 will park at the center of all 3 axes. - Enables debug logging for purging. ### End Gcode Variables + - `variable_end_print` - Determines whether to run the end print macro. - `variable_end_retract` @@ -564,7 +572,7 @@ Setting any of these values to -1 will park at the center of all 3 axes. ### Filament Change Variables - `variable_m600` - - Sets the command to be used for filament change. + - Sets the command to be used for filament change. - `variable_auto_filament_sensor` - Determines whether to automatically toggle the filament sensor. - `variable_auto_filament_delay` @@ -693,7 +701,7 @@ Each profile must consist of the following files: This file contains the patch notes for the profile. It should list the version of the profile and "initial release" if it is the first release. - **README.md** - + This file contains the profile description. It should have one header with the profile name with By: Your Name underneath. It should also have a description of the profile and any special instructions for using it. You should also briefly list the printer and components the profile was designed for. If your README file requires any images, please place them in an `images` folder within your profile folder and reference them in your README file. @@ -703,7 +711,7 @@ Each profile must consist of the following files: The main goal is to make it easy for users to quickly find the information they need to use your profile. Keep in mind that large files will increase the size of the install on every machine whether they use your profile or not. All profiles are synced alongside the rest of the repo. But only the selected profile is added to the user's config. - + Please be reasonable with the size of your images to keep the repository size small and the sync time low. - When your profile is installed on a user's printer, only the variables.cfg and config.cfg files are used. The README.md and patch_notes.txt files are only used for display purposes in the repository. Similarly, any additional files you include in your profile will not be added to the user's config. \ No newline at end of file + When your profile is installed on a user's printer, only the variables.cfg and config.cfg files are used. The README.md and patch_notes.txt files are only used for display purposes in the repository. Similarly, any additional files you include in your profile will not be added to the user's config. diff --git a/logging.cfg b/logging.cfg new file mode 100644 index 0000000..cdfed46 --- /dev/null +++ b/logging.cfg @@ -0,0 +1,177 @@ +## Copyright (C) 2023 Chris Laprade (chris@rootiest.com) +## +## This file is part of printcfg. +## +## printcfg is free software: you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## printcfg is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with printcfg. If not, see . + +########################################## +############### logger ################### +########################################## +## Parameters: ## +## TITLE: Title of the log entry ## +## MSG: Message of the log entry ## +## LEVEL: Level of the log entry ## +## OUTPUT: Output the log ## +## GLOBAL: Use global log ## +########################################## +########################################## +## NOTE: ## +## Although this macro is included in ## +## the printcfg package, it is not ## +## dependent on printcfg to function. ## +## ## +## This file can be included in any ## +## printer configuration and used in ## +## any macro you wish to have logging. ## +########################################## + +## This macro allows you to log messages and output them. +## The log is stored in the variable "log" and can be output with "logger output=1". +## The global log is stored in the variable "global" and can be output with "logger global=1". +## The log is stored in the format [title, message, level] where level is 0-7. + +## The log levels are as follows: +## 0: debug +## 1: info +## 2: notice +## 3: warning +## 4: error +## 5: critical +## 6: alert +## 7: emergency + +## Outputting the log will clear the log. +## The global log will not be cleared until the printer is restarted. + +## Examples: + +## logger title="Test" msg="This is a test" level="info" +## This will log the message "This is a test" with the title "Test" and the level "info". + +## logger title="Test" msg="This is a test" level="info" output=1 +## This will log the message "This is a test" with the title "Test" and the level "info" and output/clear the log. + +## logger +## This will output the log. + +## logger global=1 +## This will output the global log. + +## logger level="debug" +## This will output the log with the level "debug" and higher. + +## logger level="info" global=1 +## This will output the global log with the level "info" and higher. + + +[gcode_macro logger] +description: Log messages for debugging +variable_log: [] +variable_global: [] +variable_number: 0 +gcode: + {% set title = params.TITLE|default('LOG') %} ; title parameter + {% set msg = params.MSG|default('--------') %} ; message parameter + {% set level = params.LEVEL %} ; log level parameter + {% set output = params.OUTPUT|default(0)|int %} ; output parameter + {% set only_global = params.GLOBAL|default(0)|int %} ; global parameter + # Fix level strings + {% if level|lower == "info" %} + {% set level = 1 %} + {% elif level|lower == "debug" %} + {% set level = 0 %} + {% elif level|lower == "warning" %} + {% set level = 3 %} + {% elif level|lower == "error" %} + {% set level = 4 %} + {% elif level|lower == "critical" %} + {% set level = 5 %} + {% elif level|lower == "alert" %} + {% set level = 6 %} + {% elif level|lower == "emergency" %} + {% set level = 7 %} + {% else %} + {% set level = params.LEVEL|default(1)|int %} + {% endif %} + + {% macro log_print(log=log, level=1, clear=1) -%} ; create log_print macro + {% set out = [] %} ; create output array + {% for entry in log %} ; loop through logger array + # Check level 0-7 for log level + {% if entry[2] == 7 and entry[2] >= level %} ; check if level is 7 + {% set _dummy = out.append("EMERGENCY: %s: %s" % (entry[0], entry[1])) %} ; append text to output array + {% elif entry[2] == 6 and entry[2] >= level %} ; check if level is 6 + {% set _dummy = out.append("ALERT: %s: %s" % (entry[0], entry[1])) %} ; append text to output array + {% elif entry[2] == 5 and entry[2] >= level %} ; check if level is 5 + {% set _dummy = out.append("CRITICAL: %s: %s" % (entry[0], entry[1])) %} ; append text to output array + {% elif entry[2] == 4 and entry[2] >= level %} ; check if level is 4 + {% set _dummy = out.append("ERROR: %s: %s" % (entry[0], entry[1])) %} ; append text to output array + {% elif entry[2] == 3 and entry[2] >= level %} ; check if level is 3 + {% set _dummy = out.append("WARNING:%s: %s" % (entry[0], entry[1])) %} ; append text to output array + {% elif entry[2] == 2 and entry[2] >= level %} ; check if level is 2 + {% set _dummy = out.append("NOTICE: %s: %s" % (entry[0], entry[1])) %} ; append text to output array + {% elif entry[2] == 1 and entry[2] >= level %} ; check if level is 0 + {% set _dummy = out.append("INFO: %s: %s" % (entry[0], entry[1])) %} ; append text to output array + {% elif entry[2] == 0 and entry[2] >= level %} ; check if level is 3 + {% set _dummy = out.append("DEBUG: %s: %s" % (entry[0], entry[1])) %} ; append text to output array + {% endif %} + {% endfor %} + {% if clear == 1 %} + {% set _dummy = log.clear() %} ; clear logger array + {% endif %} + {% if out %} + {action_respond_info(out|join("\n"))} ; output all variables + {% else %} + {action_respond_info("No log entries found.")} ; no log to output + {% endif %} + {% endmacro -%} + + {% macro log_entry(title='LOG', msg='--------', level=0, log=log) -%} ; create logger macro + {% set entry = [title, msg, level, number] %} ; create entry array + {% set number = number + 1 %} ; increment number + {% set _dummy = log.append(entry) %} ; append text to logger array + {% endmacro -%} + + {% if params.TITLE is defined or params.MSG is defined %} ; check if title and msg are not empty + {% if only_global != 1 %} + {% if level == -1 %} + {% set level = 0 %} + {% endif %} + { log_entry(title=title, msg=msg, level=level, log=log) } ; call logger macro + {% endif %} + { log_entry(title=title, msg=msg, level=level, log=global)} ; call logger macro for global log + {% if output == true %} ; check if output is true + { log_print(log=log, level=level) } ; output log + {% endif %} + {% else %} + {% if level == -1 %} + {% set level = 1 %} + {% endif %} + {% if only_global != 1 %} + { log_print(log=log, level=level) } ; output log + {% else %} + { log_print(log=global, level=level, clear=0) } ; output log + {% endif %} + {% endif %} + +[gcode_macro TEST_LOGGER] +gcode: + {% set config = printer.configfile.settings %} ; get realtime configfile settings + {% set my_var = params.MY_VAR|default('') %} ; example parameter + logger title="Debugger" + logger msg="TEST_LOGGER" level=0 ; add macro name to log + logger title="Variable" msg={my_var} level=1 ; add variable to log + logger title="Configured Z-min" msg="{config.stepper_z.position_min}" level=2 ; add config value to log + logger title="Configured Z-max" msg="{config.stepper_z.position_max}" level=3 ; add config value to log + logger title="Debugging" msg="completed successfully" level=7 output=1 ; add debugging status to log and output log \ No newline at end of file diff --git a/print_debug.cfg b/print_debug.cfg index bbd4527..764c4c3 100644 --- a/print_debug.cfg +++ b/print_debug.cfg @@ -17,7 +17,7 @@ ##################################### ## Print Debugging ## -## Version 3.8.1 2023-5-21 ## +## Version 4.0.0 2023-6-1 ## ##################################### ## This file contains optional macros diff --git a/print_extras.cfg b/print_extras.cfg index 518b85e..d9be908 100644 --- a/print_extras.cfg +++ b/print_extras.cfg @@ -17,7 +17,7 @@ ##################################### ## Print Extras ## -## Version 3.8.1 2023-5-21 ## +## Version 4.0.0 2023-6-1 ## ##################################### ## This file contains optional config diff --git a/print_macros.cfg b/print_macros.cfg index 0df3f7e..55a6f2b 100644 --- a/print_macros.cfg +++ b/print_macros.cfg @@ -17,9 +17,11 @@ ##################################### ## Print Macros ## -## Version 3.8.1 2023-5-21 ## +## Version 4.0.0 2023-6-1 ## ##################################### +[include logging.cfg] + ################################ ######### START_PRINT ########## ################################ @@ -85,19 +87,21 @@ gcode: [gcode_macro PREP_CHAMBER] gcode: {% set printcfg = printer['gcode_macro _printcfg'] %} ; get printcfg variables - {% if printcfg.chamber_temp != 0 %} ; if chamber temp is set - M{printcfg.output} Preheating chamber ; status feedback - {% if printcfg.led_status == True %} ; if using LED status - {printcfg.status_heat} ; LED feedback - {% endif %} - {% if printcfg.chamber_type == 'temperature_fan' %} ; if using a temperature_fan chamber sensor - SET_TEMPERATURE_FAN_TARGET temperature_fan={printcfg.chamber_name} target={printcfg.chamber_temp} ; set chamber temp - {% elif printcfg.chamber_type == 'heater_generic' %} ; if using a heater_generic chamber sensor - SET_HEATER_TEMPERATURE HEATER={printcfg.chamber_name} TARGET={printcfg.chamber_temp} ; set chamber temp - {% endif %} - {% if printcfg.heat_soak == True %} ; if heat soak is enabled - SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=heat_soak_complete VALUE=0 ; set heat soak incomplete - HEAT_SOAK ; start heat soak + {% if printcfg.chamber == True %} ; if using a chamber + {% if printcfg.chamber_temp != 0 %} ; if chamber temp is set + M{printcfg.output} Preheating chamber ; status feedback + {% if printcfg.led_status == True %} ; if using LED status + {printcfg.status_heat} ; LED feedback + {% endif %} + {% if printcfg.chamber_type == 'temperature_fan' %} ; if using a temperature_fan chamber sensor + SET_TEMPERATURE_FAN_TARGET temperature_fan={printcfg.chamber_name} target={printcfg.chamber_temp} ; set chamber temp + {% elif printcfg.chamber_type == 'heater_generic' %} ; if using a heater_generic chamber sensor + SET_HEATER_TEMPERATURE HEATER={printcfg.chamber_name} TARGET={printcfg.chamber_temp} ; set chamber temp + {% endif %} + {% if printcfg.heat_soak == True %} ; if heat soak is enabled + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=heat_soak_complete VALUE=0 ; set heat soak incomplete + HEAT_SOAK ; start heat soak + {% endif %} {% endif %} {% endif %} @@ -222,7 +226,19 @@ gcode: {% if printcfg.clean_probe == True %} ; if cleaning before probing {printcfg.clean_macro} ; clean nozzle {% endif %} - ## Z-tilt or QGL + M400 ; + ## Z Calibration Functions + {% if printcfg.auto_z_calibrate == True %} ; if using auto z-calibration + {% if config.z_calibration is defined %} ; if z-calibration is configured + M{printcfg.output} Calibrating Z ; status feedback + {% if printcfg.led_status == True %} ; if using LED status + {printcfg.status_calibrating_z} ; LED feedback + {% endif %} + CALIBRATE_Z ; adjust z-calibration + {% else %} ; if z-calibration not configured + M{printcfg.error_output} Z_calibration not configured! + {% endif %} + {% endif %} {% if printcfg.z_tilt == True %} ; if using z-tilt {% if config.z_tilt is defined %} ; if z-tilt is configured M{printcfg.output} Calibrating Z ; status feedback @@ -622,6 +638,8 @@ gcode: {% if printcfg.end_speed_factor == True %} ; if end speed factor is enabled, reset it M220 S{printcfg.default_speed_factor} ; reset speed factor {% endif %} + SET_NOZZLE ; set nozzle-specific settings + SET_MATERIAL ; set material-specific settings {% endif %} @@ -1415,83 +1433,6 @@ gcode: {% endif %} {% endif %} -################################ -######### SET_CONFIGS ########## -################################ -## SET_MATERIAL -## Set Material-specific Configs -## -## Add this immediately after your start_print line of the start gcode in Prusa/SuperSlicer: -## SET_MATERIAL MATERIAL='{filament_type[initial_extruder]}' -## -## Add this immediately after your start_print line of the start gcode in Cura: -## SET_MATERIAL MATERIAL='{material_type}' -## -[gcode_macro SET_MATERIAL] -description: Set values based on material type -variable_material: '' -gcode: - {% set MATERIAL = params.MATERIAL|default('ABS')|string %} ; Get material type from slicer - SET_GCODE_VARIABLE MACRO=SET_MATERIAL VARIABLE=material VALUE='"{MATERIAL}"' ; Save the material type to a variable - {% if MATERIAL == 'PLA' %} ; If material type is PLA - #BED_MESH_PROFILE LOAD="pla_mesh" ; Load bed mesh - #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings - #SET_GCODE_OFFSET Z=0 ; Set z_offset - #SET_VELOCITY_LIMIT VELOCITY=100 ACCEL=2000 ; Set max speed/acceleration - #SET_INPUT_SHAPER SHAPER_FREQ_X=58.6 SHAPER_FREQ_Y=34.2 SHAPER_TYPE_X=mzv SHAPER_TYPE_Y=mzv ; Set input_shaper - {% elif MATERIAL == 'ABS' %} ; If material type is ABS - #BED_MESH_PROFILE LOAD="abs_mesh" ; Load bed mesh - #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings - #SET_GCODE_OFFSET Z=0 ; Set z_offset - {% elif MATERIAL == 'ABS+' %} ; If material type is ABS - #BED_MESH_PROFILE LOAD="abs_mesh" ; Load bed mesh - #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings - #SET_GCODE_OFFSET Z=0 ; Set z_offset - {% elif MATERIAL == 'PLA+' %} ; If material type is ABS - #BED_MESH_PROFILE LOAD="abs_mesh" ; Load bed mesh - #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings - #SET_GCODE_OFFSET Z=0 ; Set z_offset - {% elif MATERIAL == 'PETG' %} ; If material type is ABS - #BED_MESH_PROFILE LOAD="abs_mesh" ; Load bed mesh - #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings - #SET_GCODE_OFFSET Z=0 ; Set z_offset - {% elif MATERIAL == 'TPU' %} ; If material type is ABS - #BED_MESH_PROFILE LOAD="abs_mesh" ; Load bed mesh - #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings - #SET_GCODE_OFFSET Z=0 ; Set z_offset - {% elif MATERIAL == 'PC' %} ; If material type is ABS - #BED_MESH_PROFILE LOAD="abs_mesh" ; Load bed mesh - #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings - #SET_GCODE_OFFSET Z=0 ; Set z_offset - {%else %} ; If any other material type - #BED_MESH_PROFILE LOAD="default" ; Load bed mesh - #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings - #SET_GCODE_OFFSET Z=0 ; Set z_offset - {% endif %} - -## SET_NOZZLE -## Set nozzle-specific Configs -## -## Add this immediately after your start_print line of the start gcode in Prusa/SuperSlicer: -## SET_NOZZLE NOZZLE='{nozzle_diameter[initial_extruder]}' -## -## Add this immediately after your start_print line of the start gcode in Cura: -## SET_NOZZLE NOZZLE='{machine_nozzle_size}' -## -[gcode_macro SET_NOZZLE] -description: Set values based on nozzle diameter -variable_nozzle: 0 -gcode: - {% set NOZZLE = params.NOZZLE|default(0.4)|float %} ; Get nozzle diameter from slicer - SET_GCODE_VARIABLE MACRO=SET_NOZZLE VARIABLE=nozzle VALUE={NOZZLE} ; Save the nozzle diameter to a variable - {% if NOZZLE == 0.4 %} ; If nozzle diameter is 0.4 - SET_PRESSURE_ADVANCE ADVANCE=0.040 SMOOTH_TIME=0.040 ; Set pressure_advance settings - {% elif NOZZLE == 0.6 %} ; If nozzle diameter is 0.6 - SET_PRESSURE_ADVANCE ADVANCE=0.010 SMOOTH_TIME=0.040 ; Set pressure_advance settings - {%else %} ; If any other nozzle diameter - #SET_GCODE_OFFSET Z=0 ; Set z_offset - {% endif %} - ################################ ######## AUDIO ALERTS ########## @@ -1547,6 +1488,294 @@ gcode: #M{printcfg.output|int} Disabling filament sensor SET_FILAMENT_SENSOR SENSOR={SENSOR} ENABLE=0 +################################ +######### DOOR CONTROL ######### +################################ +## Door control macros + +### Door Variables ### +[gcode_macro _door_cfg] +variable_debounce: 0 ; <-- DO NOT CHANGE THIS VARIABLE +variable_state: 0 ; <-- DO NOT CHANGE THIS VARIABLE +variable_bounce: 0 ; <-- DO NOT CHANGE THIS VARIABLE +variable_last_door: 0 ; <-- DO NOT CHANGE THIS VARIABLE +variable_last_state: 0 ; <-- DO NOT CHANGE THIS VARIABLE + +[gcode_macro _open_door] +description: Door is opened +variable_door: 0 +gcode: + {% set doorcfg = printer['gcode_macro _door_cfg'] %} ; get doorcfg variables + {% set printcfg = printer['gcode_macro _printcfg'] %} ; get printcfg variables + {% set door = params.DOOR|default(0) %} ; get door number + {% set door_name = printcfg['door' + door] %} ; set door name + SET_GCODE_VARIABLE MACRO=_open_door VARIABLE=door VALUE={door} ; store door + {% if doorcfg.debounce == 0 %} ; check debounce + M{printcfg.output|int} Door {door_name}: Open ; status output + {printcfg.status_door_open} ; open door LEDs + {% if custom_macro == True %} ; check for custom macro + {printer['gcode_macro _printcfg'][door_macro]} ; run custom macro + {% endif %} + SET_GCODE_VARIABLE MACRO=_door_cfg VARIABLE=debounce VALUE=1 ; set debounce state + SET_GCODE_VARIABLE MACRO=_door_cfg VARIABLE=state VALUE=1 ; set door state + SET_GCODE_VARIABLE MACRO=_door_cfg VARIABLE=bounce VALUE=1 ; set door bounce + SET_GCODE_VARIABLE MACRO=_door_cfg VARIABLE=last_door VALUE={door} ; set last door + SET_GCODE_VARIABLE MACRO=_door_cfg VARIABLE=last_state VALUE=open ; set last state + UPDATE_DELAYED_GCODE ID=door_debounce DURATION={(printcfg.door_debounce / 1000)|float} ; set debounce timer + {% else %} ; bounced + SET_GCODE_VARIABLE MACRO=_door_cfg VARIABLE=bounce VALUE=1 ; set door bounce + {% endif %} + +[gcode_macro _close_door] +description: Door is closed +variable_door: 0 +gcode: + {% set doorcfg = printer['gcode_macro _door_cfg'] %} ; get doorcfg variables + {% set printcfg = printer['gcode_macro _printcfg'] %} ; get printcfg variables + {% set door = params.DOOR|default(0) %} ; get door number + {% set door_name = printcfg['door' + door] %} ; set door name + SET_GCODE_VARIABLE MACRO=_close_door VARIABLE=door VALUE={door} ; store door + {% set door_macro = "door" + door|string + "_closed" %} + {% set custom_macro = True if printer['gcode_macro _printcfg'][door_macro] is defined else False %} + {% if doorcfg.debounce == 0 %} ; check debounce + M{printcfg.output|int} Door {door}: Closed ; status output + {% if printer.virtual_sdcard.is_active == True %} ; printing state + {printcfg.status_printing} ; closed door printing LEDs + {% else %} ; idle state + {printcfg.status_ready} ; closed door idle LEDs + {% endif %} + {% if custom_macro == True %} ; check for custom macro + {printer['gcode_macro _printcfg'][door_macro]} ; run custom macro + {% endif %} + SET_GCODE_VARIABLE MACRO=_door_cfg VARIABLE=debounce VALUE=1 ; set debounce state + SET_GCODE_VARIABLE MACRO=_door_cfg VARIABLE=state VALUE=0 ; set door state + SET_GCODE_VARIABLE MACRO=_door_cfg VARIABLE=bounce VALUE=0 ; set door bounce + SET_GCODE_VARIABLE MACRO=_door_cfg VARIABLE=last_door VALUE={door} ; set last door + SET_GCODE_VARIABLE MACRO=_door_cfg VARIABLE=last_state VALUE=closed ; set last state + UPDATE_DELAYED_GCODE ID=door_debounce DURATION={(printcfg.door_debounce / 1000)|float} ; set debounce timer + {% else %} ; bounced + SET_GCODE_VARIABLE MACRO=_door_cfg VARIABLE=bounce VALUE=0 ; set door bounce + {% endif %} + + +[delayed_gcode door_debounce] +gcode: + {% set doorcfg = printer['gcode_macro _door_cfg'] %} ; get doorcfg variables + {% set printcfg = printer['gcode_macro _printcfg'] %} ; get printcfg variables + {% set door = printer['gcode_macro _doorcfg'].last_door %} ; get door number + {% set state = printer['gcode_macro _doorcfg'].last_state %} ; get door state + {% set door_macro = "door" + door|string + "_" + state|string %} ; get door macro + {% if doorcfg.bounce != doorcfg.state %} ; check if a bounce ocurred + {% if doorcfg.bounce == 1 %} ; bounced open + SET_GCODE_VARIABLE MACRO=_door_cfg VARIABLE=state VALUE=1 ; set door state + SET_GCODE_VARIABLE MACRO=_door_cfg VARIABLE=bounce VALUE=1 ; set door bounce + SET_GCODE_VARIABLE MACRO=_door_cfg VARIABLE=last_state VALUE=open ; set last state + M{printcfg.output|int} Door Open ; status output + {printcfg.status_door_open} ; open door LEDs + {% if custom_macro == True %} ; check for custom macro + {printer['gcode_macro _printcfg'][door_macro]} ; run custom macro + {% endif %} + {% else %} ; bounced closed + SET_GCODE_VARIABLE MACRO=_door_cfg VARIABLE=state VALUE=0 ; set door state + SET_GCODE_VARIABLE MACRO=_door_cfg VARIABLE=bounce VALUE=0 ; set door bounce + SET_GCODE_VARIABLE MACRO=_door_cfg VARIABLE=last_state VALUE=closed ; set last state + M{printcfg.output|int} Door Closed ; status output + {% if printer.virtual_sdcard.is_active == True %} ; printing state + {printcfg.status_printing} ; closed door printing LEDs + {% else %} ; idle state + {printcfg.status_ready} ; closed door idle LEDs + {% endif %} + {% if custom_macro == True %} ; check for custom macro + {printer['gcode_macro _printcfg'][door_macro]} ; run custom macro + {% endif %} + {% endif %} + {% endif %} + SET_GCODE_VARIABLE MACRO=_door_cfg VARIABLE=debounce VALUE=0 ; reset debounce state + +################################ +######### SIMPLE_PAUSE ######### +################################ +## This macro will determine the correct command to pause the print without any additional actions +## Example usage: +## # Pause the print +## SIMPLE_PAUSE + +## Pause the print +[gcode_macro SIMPLE_PAUSE] +description: Pause the print without any additional actions +gcode: + {% set printcfg = printer['gcode_macro _printcfg'] %} ; get printcfg variables + {% set config = printer.configfile.settings %} ; get realtime configfile settings + {% set dbg_msg = "Debugging: \nMacro: SIMPLE_PAUSE\n" %} ; set debug message"} + {% if printer['gcode_macro _CLIENT_VARIABLE'] is defined %} ; get web client variables + {% set client = printer['gcode_macro _CLIENT_VARIABLE'] %} ; get web client variables + {% set dbg_msg = dbg_msg + "Client: True\n" %} ; set debug message + {% endif %} + {% if config.pause_resume is not defined %} ; verify pause_resume feature is enabled + M{printcfg.output|int} Pause/Resume feature is not enabled + {% set dbg_msg = dbg_msg + "Pause/Resume: False\n" %} ; set debug message + {% else %} + {% set dbg_msg = dbg_msg + "Pause/Resume: True\n" %} ; set debug message + {% set pause_macro = 'gcode_macro ' + printcfg.pause_macro|string %} + {% set pause_base = 'gcode_macro ' + printcfg.pause_no_park|string %} + ## Verify macros exist + {% if printer[pause_macro] is not defined %} + M{printcfg.output|int} Pause macro does not exist + {% set dbg_msg = dbg_msg + "Pause Macro: False\n" %} ; set debug message + {% elif printer[pause_base] is not defined %} + M{printcfg.output|int} Pause without parking macro does not exist + {% set dbg_msg = dbg_msg + "Pause No Park Macro: False\n" %} ; set debug message + ## Set flag to use alternative options + {% set can_pause = False %} + {% endif %} + {% if not can_pause %} + {% set pause_base = 'gcode_macro ' + printcfg.pause|string + '_BASE' %} + {% if printer[pause_base] is defined %} + {% set pause_base = printcfg.pause|string + '_BASE' %} + {% set dbg_msg = dbg_msg + printcfg.pause|string + "_BASE Macro: True\n" %} ; set debug message + {% set can_pause = True %} + {% else %} + {% set pause_base = 'gcode_macro ' + printcfg.pause|string + '.0' %} + {% if printer[pause_base] is defined %} + {% set pause_base = printcfg.pause|string + '.0' %} + {% set dbg_msg = dbg_msg + printcfg.pause|string + ".0 Macro: True\n" %} ; set debug message + {% set can_pause = True %} + {% else %} + M{printcfg.output|int} No useable macro found, defaulting to 'PAUSE' + {% set pause_base = 'PAUSE' %} + {% set dbg_msg = dbg_msg + "Default Macro: True\n" %} ; set debug message + {% set can_pause = True %} + {% endif %} + {% endif %} + {% endif %} + {% set dbg_msg = dbg_msg + "Can Pause: " + can_pause|string + "\n" %} ; set debug message + {% set dbg_msg = dbg_msg + "Chosen macro: " + pause_base|string + "\n" %} ; set debug message + {% if can_pause %} + {% if printer.pause_resume.is_paused %} + M{printcfg.output|int} Already paused + {% set dbg_msg = dbg_msg + "Already Paused\n" %} ; set debug message + {% else %} + {% if "xyz" not in printer.toolhead.homed_axes %} + M{printcfg.output|int} Cannot pause while toolhead is not homed + {% set dbg_msg = dbg_msg + "Toolhead not homed\n" %} ; set debug message + {% else %} + {% set dbg_msg = dbg_msg + "Pause command fired: " + pause_base %} ; set debug message + {pause_base} ; pause print + {% endif %} + {% endif %} + {% endif %} + {% endif %} + {% if printcfg.debugging == True %} + {% set dbg_msg = dbg_msg + "Debugging: True\n" %} ; set debug message + M{printcfg.debug_output|int} {dbg_msg|string} + {% endif %} + +################################ +##### STORE_POSITION_MODE ###### +################################ +## These macros will: +## P500: Store the current position mode (absolute or relative) and extrusion mode (absolute or relative) in a variable. +## P501: Restore the position mode and extrusion mode from the variable. +## Example usage: +## # Store last position mode +## P500 +## # Change to relative position mode +## G91 +## # Restore last position mode +## P501 + +## Store last position mode +[gcode_macro P500] +variable_last_coords: 91 +variable_last_extrude: 83 +description: Store last position mode +gcode: + ## Store last position mode + {% if printer.gcode_move.absolute_coordinates == True %} + {% set last_coords = 90 %} + {% else %} + {% set last_coords = 91 %} + {% endif %} + {% if printer.gcode_move.absolute_extrusion == True %} + {% set last_extrude = 82 %} + {% else %} + {% set last_extrude = 83 %} + {% endif %} + SET_GCODE_VARIABLE MACRO=P500 VARIABLE=last_coords VALUE={last_coords} + SET_GCODE_VARIABLE MACRO=P500 VARIABLE=last_extrude VALUE={last_extrude} + +## Restore last position mode +[gcode_macro P501] +description: Restore last position mode +gcode: + # Get stored values + {% set last_coords = printer['gcode_macro P500'].variable_last_coords %} + {% set last_extrude = printer['gcode_macro P500'].variable_last_extrude %} + ## Get current values + {% if printer.gcode_move.absolute_coordinates == True %} + {% set coords = 90 %} + {% else %} + {% set coords = 91 %} + {% endif %} + {% if printer.gcode_move.absolute_extrusion == True %} + {% set extrude = 82 %} + {% else %} + {% set extrude = 83 %} + {% endif %} + ## Restore last position mode + {% if coords != last_coords %} + {% if coords == 90 %} + G90 + {% else %} + G91 + {% endif %} + {% endif %} + {% if extrude != last_extrude %} + {% if extrude == 82 %} + M82 + {% else %} + M83 + {% endif %} + {% endif %} + +################################ +###### SAVE/RESTORE STATE ###### +################################ +## These macros will: +## M500: Save the current state of the printer (position, extrusion, feedrate, etc.) in a variable. +## M501: Restore the state of the printer from the variable. +## Example usage: +## # Save current state +## M500 +## # Change to relative position mode +## G91 +## # MOVE X 10 +## G1 X10 +## # Restore last state +## M501 + +## Save current state +[gcode_macro M500] +description: Save current state +gcode: + ## Save the current state + SAVE_GCODE_STATE NAME=M500 + +## Restore last state +[gcode_macro M501] +description: Restore last state +gcode: + ## Check for speed parameter + {% if params.SPEED is defined %} + {% set speed = params.SPEED|default(1000)|int %} + ## Restore the last state + RESTORE_GCODE_STATE NAME=M500 MOVE=1 SPEED={speed} + {% else %} + ## Restore the last state + RESTORE_GCODE_STATE NAME=M500 MOVE=1 + {% endif %} + + ################################ ########### LAYERS ############# ################################ diff --git a/profiles/README.md b/profiles/README.md index d5a69e0..14b8de4 100644 --- a/profiles/README.md +++ b/profiles/README.md @@ -1,18 +1,18 @@ @@ -20,9 +20,10 @@ + # Preset Profiles ## [Default](./default/) @@ -31,4 +32,4 @@ This is the default configuration. Virtually all extra features are disabled in ## [Hephaestus](./hephaestus/) -This profile is for a Voron V2.4 with TAP and a nozzle brush. This is what I use on my personal machine. \ No newline at end of file +This profile is for a Voron V2.4 with TAP and a nozzle brush. This is what I use on my personal machine. diff --git a/profiles/default/config.cfg b/profiles/default/config.cfg index 2f1c2cd..fe8a547 100644 --- a/profiles/default/config.cfg +++ b/profiles/default/config.cfg @@ -17,8 +17,10 @@ ##################################### ## Print Configuration ## -## Version 3.8.1 2023-5-21 ## +## Version 4.0.0 2023-6-1 ## ##################################### +# Profile:default +# Patch:4.0.0 ##################################### ## Default Profile ## ##################################### @@ -157,17 +159,137 @@ gcode: [gcode_macro M300] description: Play a tone gcode: - {% set S = params.S|default(1000)|int %} ; S sets the tone frequency - {% set P = params.P|default(100)|int %} ; P sets the tone duration - {% set L = 0.5 %} ; L varies the PWM on time, close to 0 or 1 the tone gets a bit quieter. 0.5 is a symmetric waveform - {% if S <= 0 %} ; dont divide through zero - {% set F = 1 %} - {% set L = 0 %} - {% elif S >= 10000 %} ;max frequency set to 10kHz - {% set F = 0 %} - {% else %} - {% set F = 1/S %} ;convert frequency to seconds + +########################################################################## +################# Uncomment Below to enable beeper ####################### +########################################################################## +# {% set S = params.S|default(1000)|int %} ; S sets the tone frequency +# {% set P = params.P|default(100)|int %} ; P sets the tone duration +# {% set L = 0.5 %} ; L varies the PWM on time, close to 0 or 1 the tone gets a bit quieter. 0.5 is a symmetric waveform +# {% if S <= 0 %} ; dont divide through zero +# {% set F = 1 %} +# {% set L = 0 %} +# {% elif S >= 10000 %} ;max frequency set to 10kHz +# {% set F = 0 %} +# {% else %} +# {% set F = 1/S %} ;convert frequency to seconds +# {% endif %} +# SET_PIN PIN=_beeper VALUE={L} CYCLE_TIME={F} ;Play tone +# G4 P{P} ;tone duration +# SET_PIN PIN=_beeper VALUE=0 + +################################ +######### SET_CONFIGS ########## +################################ +## SET_MATERIAL +## Set Material-specific Configs +## +## Add this immediately after your start_print line of the start gcode in Prusa/SuperSlicer: +## SET_MATERIAL MATERIAL='{filament_type[initial_extruder]}' +## +## Add this immediately after your start_print line of the start gcode in Cura: +## SET_MATERIAL MATERIAL='{material_type}' +## +[gcode_macro SET_MATERIAL] +description: Set values based on material type +variable_material: '' +gcode: + {% set MATERIAL = params.MATERIAL|default('ABS')|string %} ; Get material type from slicer + SET_GCODE_VARIABLE MACRO=SET_MATERIAL VARIABLE=material VALUE='"{MATERIAL}"' ; Save the material type to a variable + {% if MATERIAL == 'PLA' %} ; If material type is PLA + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=0 ; Set nevermore_speed to off + #BED_MESH_PROFILE LOAD="pla_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + #SET_VELOCITY_LIMIT VELOCITY=100 ACCEL=2000 ; Set max speed/acceleration + #SET_INPUT_SHAPER SHAPER_FREQ_X=58.6 SHAPER_FREQ_Y=34.2 SHAPER_TYPE_X=mzv SHAPER_TYPE_Y=mzv ; Set input_shaper + {% elif MATERIAL == 'ABS' %} ; If material type is ABS + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=1.0 ; Set nevermore_speed to max + #BED_MESH_PROFILE LOAD="abs_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% elif MATERIAL == 'ASA' %} ; If material type is ASA + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=1.0 ; Set nevermore_speed to max + #BED_MESH_PROFILE LOAD="asa_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% elif MATERIAL == 'ABS+' %} ; If material type is ABS+ + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=1.0 ; Set nevermore_speed to max + #BED_MESH_PROFILE LOAD="abs_plus_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% elif MATERIAL == 'PLA+' %} ; If material type is PLA+ + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=0 ; Set nevermore_speed to off + #BED_MESH_PROFILE LOAD="pla_plus_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% elif MATERIAL == 'PETG' %} ; If material type is PETG + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=0 ; Set nevermore_speed to off + #BED_MESH_PROFILE LOAD="petg_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% elif MATERIAL == 'TPU' %} ; If material type is TPU + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=0 ; Set nevermore_speed to off + #BED_MESH_PROFILE LOAD="tpu_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% elif MATERIAL == 'PC' %} ; If material type is PC + #BED_MESH_PROFILE LOAD="pc_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {%else %} ; If any other material type + #BED_MESH_PROFILE LOAD="default" ; Load default bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset {% endif %} - SET_PIN PIN=_beeper VALUE={L} CYCLE_TIME={F} ;Play tone - G4 P{P} ;tone duration - SET_PIN PIN=_beeper VALUE=0 + +## SET_NOZZLE +## Set nozzle-specific Configs +## +## Add this immediately after your start_print line of the start gcode in Prusa/SuperSlicer: +## SET_NOZZLE NOZZLE='{nozzle_diameter[initial_extruder]}' +## +## Add this immediately after your start_print line of the start gcode in Cura: +## SET_NOZZLE NOZZLE='{machine_nozzle_size}' +## +[gcode_macro SET_NOZZLE] +description: Set values based on nozzle diameter +variable_nozzle: 0 +gcode: + {% set NOZZLE = params.NOZZLE|default(0.4)|float %} ; Get nozzle diameter from slicer + SET_GCODE_VARIABLE MACRO=SET_NOZZLE VARIABLE=nozzle VALUE={NOZZLE} ; Save the nozzle diameter to a variable + {% if NOZZLE == 0.4 %} ; If nozzle diameter is 0.4 + #SET_PRESSURE_ADVANCE ADVANCE=0.040 SMOOTH_TIME=0.040 ; Set pressure_advance settings + {% elif NOZZLE == 0.6 %} ; If nozzle diameter is 0.6 + #SET_PRESSURE_ADVANCE ADVANCE=0.010 SMOOTH_TIME=0.040 ; Set pressure_advance settings + {%else %} ; If any other nozzle diameter + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% endif %} + +################################ +######## Door Configs ########## +################################ + +#[gcode_button left_door] +########## IMPORTANT ########### +## ---------------------------- ## +# Set pin to match your machine: # +#pin: !PG16 # +## ---------------------------- ## +########## IMPORTANT ########### +#press_gcode: +# _close_door ; DO NOT CHANGE +#release_gcode: +# _open_door ; DO NOT CHANGE + +#[gcode_button right_door] +########## IMPORTANT ########### +## ---------------------------- ## +# Set pin to match your machine: # +#pin: !PG16 # +## ---------------------------- ## +########## IMPORTANT ########### +#press_gcode: +# _close_door ; DO NOT CHANGE +#release_gcode: +# _open_door ; DO NOT CHANGE \ No newline at end of file diff --git a/profiles/default/patch_notes.txt b/profiles/default/patch_notes.txt index 35ff736..5d8addb 100644 --- a/profiles/default/patch_notes.txt +++ b/profiles/default/patch_notes.txt @@ -2,3 +2,15 @@ - Moved z_hopped variable as it's only used by the backend. (non-critical) Remove: variable_z_hopped +3.9.0: + - Moved SET_MATERIAL and SET_NOZZLE to user_config.cfg + Add: + USER_CONFIG: + SET_MATERIAL + SET_NOZZLE +4.0.0: + - Add door control + Add: + Door Variables (see 4.0.0/vars.patch) + MANUAL: + Add '# End Custom Variables #` line before read-only variables in _printcfg macro. \ No newline at end of file diff --git a/profiles/default/patches/4.0.0/config.patch b/profiles/default/patches/4.0.0/config.patch new file mode 100644 index 0000000..d92cb16 --- /dev/null +++ b/profiles/default/patches/4.0.0/config.patch @@ -0,0 +1,116 @@ + +################################ +######### SET_CONFIGS ########## +################################ +## SET_MATERIAL +## Set Material-specific Configs +## +## Add this immediately after your start_print line of the start gcode in Prusa/SuperSlicer: +## SET_MATERIAL MATERIAL='{filament_type[initial_extruder]}' +## +## Add this immediately after your start_print line of the start gcode in Cura: +## SET_MATERIAL MATERIAL='{material_type}' +## +[gcode_macro SET_MATERIAL] +description: Set values based on material type +variable_material: '' +gcode: + {% set MATERIAL = params.MATERIAL|default('ABS')|string %} ; Get material type from slicer + SET_GCODE_VARIABLE MACRO=SET_MATERIAL VARIABLE=material VALUE='"{MATERIAL}"' ; Save the material type to a variable + {% if MATERIAL == 'PLA' %} ; If material type is PLA + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=0 ; Set nevermore_speed to off + #BED_MESH_PROFILE LOAD="pla_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + #SET_VELOCITY_LIMIT VELOCITY=100 ACCEL=2000 ; Set max speed/acceleration + #SET_INPUT_SHAPER SHAPER_FREQ_X=58.6 SHAPER_FREQ_Y=34.2 SHAPER_TYPE_X=mzv SHAPER_TYPE_Y=mzv ; Set input_shaper + {% elif MATERIAL == 'ABS' %} ; If material type is ABS + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=1.0 ; Set nevermore_speed to max + #BED_MESH_PROFILE LOAD="abs_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% elif MATERIAL == 'ASA' %} ; If material type is ASA + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=1.0 ; Set nevermore_speed to max + #BED_MESH_PROFILE LOAD="asa_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% elif MATERIAL == 'ABS+' %} ; If material type is ABS+ + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=1.0 ; Set nevermore_speed to max + #BED_MESH_PROFILE LOAD="abs_plus_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% elif MATERIAL == 'PLA+' %} ; If material type is PLA+ + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=0 ; Set nevermore_speed to off + #BED_MESH_PROFILE LOAD="pla_plus_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% elif MATERIAL == 'PETG' %} ; If material type is PETG + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=0 ; Set nevermore_speed to off + #BED_MESH_PROFILE LOAD="petg_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% elif MATERIAL == 'TPU' %} ; If material type is TPU + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=0 ; Set nevermore_speed to off + #BED_MESH_PROFILE LOAD="tpu_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% elif MATERIAL == 'PC' %} ; If material type is PC + #BED_MESH_PROFILE LOAD="pc_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {%else %} ; If any other material type + #BED_MESH_PROFILE LOAD="default" ; Load default bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% endif %} + +## SET_NOZZLE +## Set nozzle-specific Configs +## +## Add this immediately after your start_print line of the start gcode in Prusa/SuperSlicer: +## SET_NOZZLE NOZZLE='{nozzle_diameter[initial_extruder]}' +## +## Add this immediately after your start_print line of the start gcode in Cura: +## SET_NOZZLE NOZZLE='{machine_nozzle_size}' +## +[gcode_macro SET_NOZZLE] +description: Set values based on nozzle diameter +variable_nozzle: 0 +gcode: + {% set NOZZLE = params.NOZZLE|default(0.4)|float %} ; Get nozzle diameter from slicer + SET_GCODE_VARIABLE MACRO=SET_NOZZLE VARIABLE=nozzle VALUE={NOZZLE} ; Save the nozzle diameter to a variable + {% if NOZZLE == 0.4 %} ; If nozzle diameter is 0.4 + #SET_PRESSURE_ADVANCE ADVANCE=0.040 SMOOTH_TIME=0.040 ; Set pressure_advance settings + {% elif NOZZLE == 0.6 %} ; If nozzle diameter is 0.6 + #SET_PRESSURE_ADVANCE ADVANCE=0.010 SMOOTH_TIME=0.040 ; Set pressure_advance settings + {%else %} ; If any other nozzle diameter + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% endif %} + +################################ +######## Door Configs ########## +################################ + +#[gcode_button left_door] +########## IMPORTANT ########### +## ---------------------------- ## +# Set pin to match your machine: # +#pin: !PG16 # +## ---------------------------- ## +########## IMPORTANT ########### +#press_gcode: +# _close_door ; DO NOT CHANGE +#release_gcode: +# _open_door ; DO NOT CHANGE + +#[gcode_button right_door] +########## IMPORTANT ########### +## ---------------------------- ## +# Set pin to match your machine: # +#pin: !PG16 # +## ---------------------------- ## +########## IMPORTANT ########### +#press_gcode: +# _close_door ; DO NOT CHANGE +#release_gcode: +# _open_door ; DO NOT CHANGE \ No newline at end of file diff --git a/profiles/default/patches/4.0.0/vars.patch b/profiles/default/patches/4.0.0/vars.patch new file mode 100644 index 0000000..b0c9749 --- /dev/null +++ b/profiles/default/patches/4.0.0/vars.patch @@ -0,0 +1,24 @@ + +## Door Switch Variables +variable_doors: 0 ; Number of doors (0, 1 or 2) +variable_door1: 'left_door' ; Name of first door switch +variable_door2: 'right_door' ; Name of second door switch +## Note: Additional door switches can be added here (e.g. variable_door3, variable_door4, etc.) +variable_door_debounce: 250 ; Debounce time for door switch (ms) +variable_status_door_open: '_STATUS_BRIGHT' ; Status to show when door is open +variable_door_open_gcode: 'M116' ; Custom macro for open doors (set to 'M116' to disable) +variable_door_closed_gcode: 'M116' ; Custom macro for closed doors (set to 'M116' to disable) + +## Z Calibration Variables +variable_z_calibrate: False + +## Default Offset +variable_offset_store: False ; If True, the z-offset will be saved to the config at the end of a print + +## Debugging Variables +## NOTE: These variables configure debugging +## behavior. They are used to enable +## or disable debugging output and +## to define the debug output level. +variable_debugging: True +variable_debug_level: 0 diff --git a/profiles/default/variables.cfg b/profiles/default/variables.cfg index 784d379..c352e25 100644 --- a/profiles/default/variables.cfg +++ b/profiles/default/variables.cfg @@ -17,8 +17,10 @@ ##################################### ## User Profile ## -## Version 3.8.1 2023-5-21 ## +## Version 4.0.0 2023-6-1 ## ##################################### +# Profile:default +# Patch:4.0.0 ##################################### ## Default Profile ## ##################################### @@ -36,7 +38,7 @@ ## printcfg Configuration Variables ## Variables file version -variable_version: '3.8.0' +variable_version: '4.0.0' ## Default temperatures variable_extruder_temp: 200 @@ -44,7 +46,10 @@ variable_extruder_pretemp: 0 variable_bed_temp: 60 ## Default Offset -variable_z_offset: 0.0 +variable_z_offset: 0.0 ; Default z-offset adjustment to be applied to prints +variable_start_offset: False ; If True, the z-offset will be applied at the start of the print +variable_end_offset: True ; If True, the z-offset will be removed at the end of the print +variable_offset_store: False ; If True, the z-offset will be saved to the config at the end of a print ## Chamber Variables variable_chamber_type: 'none' @@ -53,12 +58,12 @@ variable_chamber_temp: 35 variable_chamber_time: 10 ## Soaking Variables -variable_heat_soak: True +variable_heat_soak: False variable_time_soak: False variable_temp_soak: True ## Bed Fan Variables -variable_bed_fan: True +variable_bed_fan: False variable_bed_fan_fast: 'BEDFANSFAST' variable_bed_fan_slow: 'BEDFANSSLOW' variable_bed_fan_stop: 'BEDFANSOFF' @@ -72,13 +77,13 @@ variable_soak_idle_time: 18000 ## Idle Action Variables variable_idle_extruder: True variable_idle_bed: True -variable_idle_chamber: True +variable_idle_chamber: False variable_idle_steppers: True -variable_idle_power: True +variable_idle_power: False ## Parking Variables variable_park_x: 25 -variable_park_y: 300 +variable_park_y: 25 variable_park_z: 50 variable_park_zrel: 10 variable_park_zmin: 50 @@ -87,8 +92,8 @@ variable_park_extrude: 1.0 variable_park_base: '_TOOLHEAD_PARK_PAUSE_CANCEL' ## Preheat Parking Variables -variable_preheat_x: 145 -variable_preheat_y: 153 +variable_preheat_x: 10 +variable_preheat_y: 10 variable_preheat_z: 10 ## Maintenance Parking Variables @@ -97,8 +102,8 @@ variable_maint_y: -1 variable_maint_z: -1 ## Homing Variables -variable_home_x: 145 -variable_home_y: 153 +variable_home_x: 112 +variable_home_y: 112 variable_pre_home_z: 2.0 ; Enable force_move to use this feature variable_post_home_z: 10 variable_home_travel_speed: 10000 @@ -119,14 +124,12 @@ variable_pause_no_park: 'PAUSE_BASE' ## Speed Variables variable_default_speed_factor: 100 -variable_start_offset: False variable_start_speed_factor: False -variable_end_offset: True variable_end_speed_factor: True variable_travel_speed: 300 ## Filter Variables -variable_nevermore: True +variable_nevermore: False variable_nevermore_name: 'nevermore' variable_nevermore_type: 'fan_generic' variable_nevermore_speed: 1.0 @@ -153,8 +156,9 @@ variable_attach_macro: 'Attach_Probe_Lock' variable_dock_macro: 'Dock_Probe_Unlock' ## Z Calibration Variables +variable_z_calibrate: False variable_z_tilt: False -variable_qgl: True +variable_qgl: False ## Meshing Variables variable_bed_mesh: True @@ -166,14 +170,14 @@ variable_mesh_fuzz_min: 0 # If enabled, the minimum amount in variable_mesh_fuzz_max: 4 # If enabled, the maximum amount in mm a probe point can be randomized, default is 4. ## Nozzle Cleaning Variables -variable_cleaning: True +variable_cleaning: False variable_clean_probe: True variable_clean_end: False variable_post_clean_home: False variable_clean_m600: True variable_clean_macro: 'CLEAN_NOZZLE' variable_clean_x: 50 -variable_clean_y: 303 +variable_clean_y: 50 variable_clean_z: 5 variable_clean_wipe_axis: 'X' variable_clean_wipe_dist: 50 @@ -200,7 +204,7 @@ variable_purge_debug: False ## End Gcode Variables variable_end_print: True -variable_end_retract: True +variable_end_retract: False variable_end_retract_length: 15 variable_end_retract_speed: 60 variable_power_off: False @@ -230,7 +234,7 @@ variable_output: 118 # Select 116, 117, or 118 to specify out variable_error_output: 118 ## LED Status Variables -variable_led_status: True # Use LED Status macros such as on the stealthburner +variable_led_status: False # Use LED Status macros such as on the stealthburner variable_status_ready: '_STATUS_READY' variable_status_busy: '_STATUS_BUSY' variable_status_preprint: '_STATUS_PREPRINT' @@ -247,7 +251,7 @@ variable_status_error: '_STATUS_ERROR' variable_status_printing: '_STATUS_PRINTING' ## Audio Status Variables -variable_audio_status: True # Use audio feedback macros +variable_audio_status: False # Use audio feedback macros variable_start_audio: '_PRINT_START_TUNE' variable_error_audio: '_GAME_OVER_TUNE' variable_success_audio: '_MARIO_TUNE' @@ -259,6 +263,26 @@ variable_alert_freq: 5 variable_use_telegram: False # Use Telegram feedback macros variable_telegram_runout: 'TELEGRAM_FILAMENT_RUNOUT' +## Door Switch Variables +variable_doors: 0 ; Number of doors (0, 1 or 2) +variable_door1: 'left_door' ; Name of first door switch +variable_door2: 'right_door' ; Name of second door switch +## Note: Additional door switches can be added here (e.g. variable_door3, variable_door4, etc.) +variable_door_debounce: 250 ; Debounce time for door switch (ms) +variable_status_door_open: '_STATUS_BRIGHT' ; Status to show when door is open +variable_door_open_gcode: 'M116' ; Custom macro for open doors (set to 'M116' to disable) +variable_door_closed_gcode: 'M116' ; Custom macro for closed doors (set to 'M116' to disable) + +## Debugging Variables +## NOTE: These variables configure debugging +## behavior. They are used to enable +## or disable debugging output and +## to define the debug output level. +variable_debugging: False +variable_debug_level: 0 + +# End Custom Variables # + ############################################################################################################# #################################### Do not edit below this line ############################################ ############################################################################################################# @@ -285,8 +309,8 @@ gcode: # No gcode needed ## Mainsail Client Macro Variables [gcode_macro _CLIENT_VARIABLE] variable_use_custom_pos : False ; use custom park coordinates for x,y [True/False] -variable_custom_park_x : 50.0 ; custom x position; value must be within your defined min and max of X -variable_custom_park_y : 302.0 ; custom y position; value must be within your defined min and max of Y +variable_custom_park_x : 50.0 ; custom x position; value must be within your defined min and max of X +variable_custom_park_y : 50.0 ; custom y position; value must be within your defined min and max of Y variable_custom_park_dz : 2.0 ; custom dz value; the value in mm to lift the nozzle when move to park position variable_retract : 1.0 ; the value to retract while PAUSE variable_cancel_retract : 5.0 ; the value to retract while CANCEL_PRINT @@ -295,9 +319,9 @@ variable_unretract : 1.0 ; the value to unretract while RESUME variable_speed_unretract : 35.0 ; unretract speed in mm/s variable_speed_hop : 15.0 ; z move speed in mm/s variable_speed_move : 100.0 ; move speed in mm/s -variable_park_at_cancel : True ; allow to move the toolhead to park while execute CANCEL_PRINT [True/False] +variable_park_at_cancel : True ; allow to move the toolhead to park while execute CANCEL_PRINT [True/False] variable_park_at_cancel_x : 50.0 ; different park position during CANCEL_PRINT [None/Position as Float]; park_at_cancel must be True -variable_park_at_cancel_y : 302.0 ; different park position during CANCEL_PRINT [None/Position as Float]; park_at_cancel must be True +variable_park_at_cancel_y : 50.0 ; different park position during CANCEL_PRINT [None/Position as Float]; park_at_cancel must be True ## !!! Caution [firmware_retraction] must be defined in the printer.cfg if you set use_fw_retract: True !!! variable_use_fw_retract : True ; use fw_retraction instead of the manual version [True/False] gcode: diff --git a/profiles/hephaestus/config.cfg b/profiles/hephaestus/config.cfg index 0aeb3cb..d10f38e 100644 --- a/profiles/hephaestus/config.cfg +++ b/profiles/hephaestus/config.cfg @@ -17,8 +17,10 @@ ##################################### ## Print Configuration ## -## Version 3.8.1 2023-5-21 ## +## Version 4.0.0 2023-5-20 ## ##################################### +# Profile:hephaestus +# Patch:4.0.0 ##################################### ## Hephaestus Profile ## ##################################### @@ -171,3 +173,118 @@ gcode: SET_PIN PIN=_beeper VALUE={L} CYCLE_TIME={F} ;Play tone G4 P{P} ;tone duration SET_PIN PIN=_beeper VALUE=0 +################################ +######### SET_CONFIGS ########## +################################ +## SET_MATERIAL +## Set Material-specific Configs +## +## Add this immediately after your start_print line of the start gcode in Prusa/SuperSlicer: +## SET_MATERIAL MATERIAL='{filament_type[initial_extruder]}' +## +## Add this immediately after your start_print line of the start gcode in Cura: +## SET_MATERIAL MATERIAL='{material_type}' +## +[gcode_macro SET_MATERIAL] +description: Set values based on material type +variable_material: '' +gcode: + {% set MATERIAL = params.MATERIAL|default('ABS')|string %} ; Get material type from slicer + SET_GCODE_VARIABLE MACRO=SET_MATERIAL VARIABLE=material VALUE='"{MATERIAL}"' ; Save the material type to a variable + {% if MATERIAL == 'PLA' %} ; If material type is PLA + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=0 ; Set nevermore_speed to off + #BED_MESH_PROFILE LOAD="pla_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + #SET_VELOCITY_LIMIT VELOCITY=100 ACCEL=2000 ; Set max speed/acceleration + #SET_INPUT_SHAPER SHAPER_FREQ_X=58.6 SHAPER_FREQ_Y=34.2 SHAPER_TYPE_X=mzv SHAPER_TYPE_Y=mzv ; Set input_shaper + {% elif MATERIAL == 'ABS' %} ; If material type is ABS + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=1.0 ; Set nevermore_speed to max + #BED_MESH_PROFILE LOAD="abs_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% elif MATERIAL == 'ASA' %} ; If material type is ASA + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=1.0 ; Set nevermore_speed to max + #BED_MESH_PROFILE LOAD="asa_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% elif MATERIAL == 'ABS+' %} ; If material type is ABS+ + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=1.0 ; Set nevermore_speed to max + #BED_MESH_PROFILE LOAD="abs_plus_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% elif MATERIAL == 'PLA+' %} ; If material type is PLA+ + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=0 ; Set nevermore_speed to off + #BED_MESH_PROFILE LOAD="pla_plus_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% elif MATERIAL == 'PETG' %} ; If material type is PETG + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=0 ; Set nevermore_speed to off + #BED_MESH_PROFILE LOAD="petg_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% elif MATERIAL == 'TPU' %} ; If material type is TPU + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=0 ; Set nevermore_speed to off + #BED_MESH_PROFILE LOAD="tpu_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% elif MATERIAL == 'PC' %} ; If material type is PC + #BED_MESH_PROFILE LOAD="pc_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {%else %} ; If any other material type + #BED_MESH_PROFILE LOAD="default" ; Load default bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% endif %} + +## SET_NOZZLE +## Set nozzle-specific Configs +## +## Add this immediately after your start_print line of the start gcode in Prusa/SuperSlicer: +## SET_NOZZLE NOZZLE='{nozzle_diameter[initial_extruder]}' +## +## Add this immediately after your start_print line of the start gcode in Cura: +## SET_NOZZLE NOZZLE='{machine_nozzle_size}' +## +[gcode_macro SET_NOZZLE] +description: Set values based on nozzle diameter +variable_nozzle: 0 +gcode: + {% set NOZZLE = params.NOZZLE|default(0.4)|float %} ; Get nozzle diameter from slicer + SET_GCODE_VARIABLE MACRO=SET_NOZZLE VARIABLE=nozzle VALUE={NOZZLE} ; Save the nozzle diameter to a variable + {% if NOZZLE == 0.4 %} ; If nozzle diameter is 0.4 + #SET_PRESSURE_ADVANCE ADVANCE=0.040 SMOOTH_TIME=0.040 ; Set pressure_advance settings + {% elif NOZZLE == 0.6 %} ; If nozzle diameter is 0.6 + #SET_PRESSURE_ADVANCE ADVANCE=0.010 SMOOTH_TIME=0.040 ; Set pressure_advance settings + {%else %} ; If any other nozzle diameter + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% endif %} + +################################ +######## Door Configs ########## +################################ + +[gcode_button doors] +########## IMPORTANT ########### +## ---------------------------- ## +# Set pin to match your machine: # +pin: !PG15 # +## ---------------------------- ## +########## IMPORTANT ########### +press_gcode: + _close_door ; DO NOT CHANGE +release_gcode: + _open_door ; DO NOT CHANGE + +#[gcode_button right_door] +########## IMPORTANT ########### +## ---------------------------- ## +# Set pin to match your machine: # +#pin: !PG16 # +## ---------------------------- ## +########## IMPORTANT ########### +#press_gcode: +# _close_door ; DO NOT CHANGE +#release_gcode: +# _open_door ; DO NOT CHANGE diff --git a/profiles/hephaestus/patch_notes.txt b/profiles/hephaestus/patch_notes.txt index 35ff736..5d8addb 100644 --- a/profiles/hephaestus/patch_notes.txt +++ b/profiles/hephaestus/patch_notes.txt @@ -2,3 +2,15 @@ - Moved z_hopped variable as it's only used by the backend. (non-critical) Remove: variable_z_hopped +3.9.0: + - Moved SET_MATERIAL and SET_NOZZLE to user_config.cfg + Add: + USER_CONFIG: + SET_MATERIAL + SET_NOZZLE +4.0.0: + - Add door control + Add: + Door Variables (see 4.0.0/vars.patch) + MANUAL: + Add '# End Custom Variables #` line before read-only variables in _printcfg macro. \ No newline at end of file diff --git a/profiles/hephaestus/patches/4.0.0/config.patch b/profiles/hephaestus/patches/4.0.0/config.patch new file mode 100644 index 0000000..fe4f638 --- /dev/null +++ b/profiles/hephaestus/patches/4.0.0/config.patch @@ -0,0 +1,116 @@ + +################################ +######### SET_CONFIGS ########## +################################ +## SET_MATERIAL +## Set Material-specific Configs +## +## Add this immediately after your start_print line of the start gcode in Prusa/SuperSlicer: +## SET_MATERIAL MATERIAL='{filament_type[initial_extruder]}' +## +## Add this immediately after your start_print line of the start gcode in Cura: +## SET_MATERIAL MATERIAL='{material_type}' +## +[gcode_macro SET_MATERIAL] +description: Set values based on material type +variable_material: '' +gcode: + {% set MATERIAL = params.MATERIAL|default('ABS')|string %} ; Get material type from slicer + SET_GCODE_VARIABLE MACRO=SET_MATERIAL VARIABLE=material VALUE='"{MATERIAL}"' ; Save the material type to a variable + {% if MATERIAL == 'PLA' %} ; If material type is PLA + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=0 ; Set nevermore_speed to off + #BED_MESH_PROFILE LOAD="pla_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + #SET_VELOCITY_LIMIT VELOCITY=100 ACCEL=2000 ; Set max speed/acceleration + #SET_INPUT_SHAPER SHAPER_FREQ_X=58.6 SHAPER_FREQ_Y=34.2 SHAPER_TYPE_X=mzv SHAPER_TYPE_Y=mzv ; Set input_shaper + {% elif MATERIAL == 'ABS' %} ; If material type is ABS + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=1.0 ; Set nevermore_speed to max + #BED_MESH_PROFILE LOAD="abs_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% elif MATERIAL == 'ASA' %} ; If material type is ASA + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=1.0 ; Set nevermore_speed to max + #BED_MESH_PROFILE LOAD="asa_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% elif MATERIAL == 'ABS+' %} ; If material type is ABS+ + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=1.0 ; Set nevermore_speed to max + #BED_MESH_PROFILE LOAD="abs_plus_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% elif MATERIAL == 'PLA+' %} ; If material type is PLA+ + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=0 ; Set nevermore_speed to off + #BED_MESH_PROFILE LOAD="pla_plus_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% elif MATERIAL == 'PETG' %} ; If material type is PETG + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=0 ; Set nevermore_speed to off + #BED_MESH_PROFILE LOAD="petg_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% elif MATERIAL == 'TPU' %} ; If material type is TPU + SET_GCODE_VARIABLE MACRO=_printcfg VARIABLE=nevermore_speed VALUE=0 ; Set nevermore_speed to off + #BED_MESH_PROFILE LOAD="tpu_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% elif MATERIAL == 'PC' %} ; If material type is PC + #BED_MESH_PROFILE LOAD="pc_mesh" ; Load bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {%else %} ; If any other material type + #BED_MESH_PROFILE LOAD="default" ; Load default bed mesh + #SET_PRESSURE_ADVANCE ADVANCE=0.035 SMOOTH_TIME=0.040 ; Set pressure_advance settings + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% endif %} + +## SET_NOZZLE +## Set nozzle-specific Configs +## +## Add this immediately after your start_print line of the start gcode in Prusa/SuperSlicer: +## SET_NOZZLE NOZZLE='{nozzle_diameter[initial_extruder]}' +## +## Add this immediately after your start_print line of the start gcode in Cura: +## SET_NOZZLE NOZZLE='{machine_nozzle_size}' +## +[gcode_macro SET_NOZZLE] +description: Set values based on nozzle diameter +variable_nozzle: 0 +gcode: + {% set NOZZLE = params.NOZZLE|default(0.4)|float %} ; Get nozzle diameter from slicer + SET_GCODE_VARIABLE MACRO=SET_NOZZLE VARIABLE=nozzle VALUE={NOZZLE} ; Save the nozzle diameter to a variable + {% if NOZZLE == 0.4 %} ; If nozzle diameter is 0.4 + #SET_PRESSURE_ADVANCE ADVANCE=0.040 SMOOTH_TIME=0.040 ; Set pressure_advance settings + {% elif NOZZLE == 0.6 %} ; If nozzle diameter is 0.6 + #SET_PRESSURE_ADVANCE ADVANCE=0.010 SMOOTH_TIME=0.040 ; Set pressure_advance settings + {%else %} ; If any other nozzle diameter + #SET_GCODE_OFFSET Z=0 ; Set z_offset + {% endif %} + +################################ +######## Door Configs ########## +################################ + +[gcode_button doors] +########## IMPORTANT ########### +## ---------------------------- ## +# Set pin to match your machine: # +pin: !PG15 # +## ---------------------------- ## +########## IMPORTANT ########### +press_gcode: + _close_door ; DO NOT CHANGE +release_gcode: + _open_door ; DO NOT CHANGE + +#[gcode_button right_door] +########## IMPORTANT ########### +## ---------------------------- ## +# Set pin to match your machine: # +#pin: !PG16 # +## ---------------------------- ## +########## IMPORTANT ########### +#press_gcode: +# _close_door ; DO NOT CHANGE +#release_gcode: +# _open_door ; DO NOT CHANGE diff --git a/profiles/hephaestus/patches/4.0.0/vars.patch b/profiles/hephaestus/patches/4.0.0/vars.patch new file mode 100644 index 0000000..2e184a3 --- /dev/null +++ b/profiles/hephaestus/patches/4.0.0/vars.patch @@ -0,0 +1,24 @@ + +## Door Switch Variables +variable_doors: 1 ; Number of doors (0, 1 or 2) +variable_door1: 'doors' ; Name of first door switch +variable_door2: 'right_door' ; Name of second door switch +## Note: Additional door switches can be added here (e.g. variable_door3, variable_door4, etc.) +variable_door_debounce: 250 ; Debounce time for door switch (ms) +variable_status_door_open: '_STATUS_BRIGHT' ; Status to show when door is open +variable_door_open_gcode: 'M116' ; Custom macro for open doors (set to 'M116' to disable) +variable_door_closed_gcode: 'M116' ; Custom macro for closed doors (set to 'M116' to disable) + +## Z Calibration Variables +variable_z_calibrate: False + +## Default Offset +variable_offset_store: False ; If True, the z-offset will be saved to the config at the end of a print + +## Debugging Variables +## NOTE: These variables configure debugging +## behavior. They are used to enable +## or disable debugging output and +## to define the debug output level. +variable_debugging: True +variable_debug_level: 0 diff --git a/profiles/hephaestus/variables.cfg b/profiles/hephaestus/variables.cfg index 6c66c41..4a2e0ce 100644 --- a/profiles/hephaestus/variables.cfg +++ b/profiles/hephaestus/variables.cfg @@ -17,8 +17,10 @@ ##################################### ## User Profile ## -## Version 3.8.1 2023-5-21 ## +## Version 4.0.0 2023-6-1 ## ##################################### +# Profile:hephaestus +# Patch:4.0.0 ##################################### ## Hephaestus Profile ## ##################################### @@ -36,7 +38,7 @@ ## printcfg Configuration Variables ## Variables file version -variable_version: '3.8.0' +variable_version: '4.0.0' ## Default temperatures variable_extruder_temp: 240 @@ -259,6 +261,18 @@ variable_alert_freq: 5 variable_use_telegram: False # Use Telegram feedback macros variable_telegram_runout: 'TELEGRAM_FILAMENT_RUNOUT' +## Door Switch Variables +variable_doors: 1 ; Number of doors (0, 1 or 2) +variable_door1: 'doors' ; Name of first door switch +variable_door2: 'right_door' ; Name of second door switch +## Note: Additional door switches can be added here (e.g. variable_door3, variable_door4, etc.) +variable_door_debounce: 250 ; Debounce time for door switch (ms) +variable_status_door_open: '_STATUS_BRIGHT' ; Status to show when door is open +variable_door_open_gcode: 'M116' ; Custom macro for open doors (set to 'M116' to disable) +variable_door_closed_gcode: 'M116' ; Custom macro for closed doors (set to 'M116' to disable) + +# End Custom Variables # + ############################################################################################################# #################################### Do not edit below this line ############################################ ############################################################################################################# diff --git a/scripts/change_profile.sh b/scripts/change_profile.sh new file mode 100644 index 0000000..1fea609 --- /dev/null +++ b/scripts/change_profile.sh @@ -0,0 +1,336 @@ +#!/bin/bash + +# Copyright (C) 2023 Chris Laprade (chris@rootiest.com) +# +# This file is part of printcfg. +# +# printcfg is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# printcfg is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with printcfg. If not, see . + +##################################### +## Printcfg Profile Change ## +## Version 4.0.0 2023-6-1 ## +##################################### + +# This script will change the user profile to the specified profile. +# Arguments: +# $1: (mandatory) + +#################################################################################################### + +# Example: +# ./change_profile.sh default +# This will change the user profile to the default profile. + +#################################################################################################### + +# Set the dev and repo name +dev="rootiest" +repo="printcfg" +branch="master" +# Get home directory +home=$(eval echo ~$USER) +# Define the klipper config file +config=$home/printer_data/config +# Define the printer.cfg and moonraker.conf files +printer=$home/printer_data/config/printer.cfg +moonraker=$home/printer_data/config/moonraker.conf +# Set the default profile +default_src=default +user_vars=$config/user_profile.cfg +old_user_vars=$config/$repo/user_profile.cfg +user_cfg=$config/user_config.cfg +old_user_cfg=$config/$repo/user_config.cfg +profile_pattern="# Profile:(.*)" + +# Check if any parameters were provided +if [ $# -eq 0 ] +then + echo -e "\n\e[31mERROR: No profile name provided.\e[0m" + echo "Usage: ./change_profile.sh " + exit 1 +else + # Set the profile name + if [ -n "$1" ] + then + if [ "$1" == "backup" ] + then + src_vars=$config/user_profile.cfg.bak + src_cfg=$config/user_config.cfg.bak + src_path=$config + else + src_vars=$config/$repo/profiles/$1/variables.cfg + src_cfg=$config/$repo/profiles/$1/config.cfg + src_path=$config/$repo/profiles/$1 + fi + fi +fi + +echo -e "\nChanging profile to $1..." + +# Check if the profile exists +if [ ! -d "$src_path" ] +then + echo -e "\n\e[31mERROR: Profile $1 does not exist.\e[0m" + echo "Usage: ./change_profile.sh " + exit 1 +fi + +# Check if the profile is already active +if [ -f "$user_vars" ] +then + # Search for the profile_pattern in the user_vars using grep + vars_profile=$(grep -oP "$profile_pattern" "$user_vars" | cut -d':' -f2) + # Verify that the profile marker was found + if [ -z "$vars_profile" ] + then + echo -e "\n\e[31mERROR: Profile marker not found in $user_vars.\e[0m" + echo "Usage: ./change_profile.sh " + exit 1 + fi + # Search for the profile_pattern in the src_vars using grep + src_profile=$(grep -oP "$profile_pattern" "$src_vars" | cut -d':' -f2) + # Verify that the profile marker was found + if [ -z "$src_profile" ] + then + echo -e "\n\e[31mERROR: Profile marker not found in $src_vars.\e[0m" + echo "Usage: ./change_profile.sh " + exit 1 + fi + # Check if the profile is already active + if [ "$vars_profile" == "$src_profile" ] + then + echo -e "\n\e[31mERROR: Profile $1 is already active.\e[0m" + echo "Usage: ./change_profile.sh " + exit 1 + fi +fi + +# Check if the user config file exists +if [ -f "$user_cfg" ] +then + # Search for the profile_pattern in the user_cfg using grep + cfg_profile=$(grep -oP "$profile_pattern" "$user_cfg" | cut -d':' -f2) + # Verify that the profile marker was found + if [ -z "$cfg_profile" ] + then + echo -e "\n\e[31mERROR: Profile marker not found in $user_cfg.\e[0m" + echo "Usage: ./change_profile.sh " + exit 1 + fi + # Search for the profile_pattern in the src_cfg using grep + src_profile=$(grep -oP "$profile_pattern" "$src_cfg" | cut -d':' -f2) + # Verify that the profile marker was found + if [ -z "$src_profile" ] + then + echo -e "\n\e[31mERROR: Profile marker not found in $src_cfg.\e[0m" + echo "Usage: ./change_profile.sh " + exit 1 + fi + # Check if the profile is already active + if [ "$cfg_profile" == "$src_profile" ] + then + echo -e "\n\e[31mERROR: Profile $1 is already active.\e[0m" + echo "Usage: ./change_profile.sh " + exit 1 + fi +fi + +# Check if source file extensions end in .bak +if [ "${src_vars: -4}" == ".bak" ] +then + # Copy them to a temp file + cp "$src_vars" "$src_vars.tmp" + src_vars="$src_vars.tmp" +fi +if [ "${src_cfg: -4}" == ".bak" ] +then + # Copy them to a temp file + cp "$src_cfg" "$src_cfg.tmp" + src_cfg="$src_cfg.tmp" +fi + +# Backup the current user profile +if [ -f "$user_vars" ] +then + # Check if the backup already exists + if [ -f "$user_vars.bak" ] + then + # Rename the backup + cp "$user_vars.bak" "$user_vars.old" + # Verify that the rename was successful + if [ $? -ne 0 ] + then + echo -e "\n\e[31mERROR: Failed to rename $user_vars.bak to $user_vars.old.\e[0m" + echo "Usage: ./change_profile.sh " + exit 1 + fi + fi + # Backup the current user profile + cp "$user_vars" "$user_vars.bak" + # Verify that the backup was successful + if [ $? -ne 0 ] + then + echo -e "\n\e[31mERROR: Failed to backup $user_vars.\e[0m" + echo "Usage: ./change_profile.sh " + exit 1 + fi +fi + +# Backup the current user config +if [ -f "$user_cfg" ] +then + # Check if the backup already exists + if [ -f "$user_cfg.bak" ] + then + # Rename the backup + cp "$user_cfg.bak" "$user_cfg.old" + # Verify that the rename was successful + if [ $? -ne 0 ] + then + echo -e "\n\e[31mERROR: Failed to rename $user_cfg.bak to $user_cfg.old.\e[0m" + echo "Usage: ./change_profile.sh " + exit 1 + fi + fi + # Backup the current user config + cp "$user_cfg" "$user_cfg.bak" + # Verify that the backup was successful + if [ $? -ne 0 ] + then + echo -e "\n\e[31mERROR: Failed to backup $user_cfg.\e[0m" + echo "Usage: ./change_profile.sh " + exit 1 + fi +fi + +# Apply the new profile +if [ -f "$user_vars" ] +then + # Copy the new profile to the user profile + cp "$src_vars" "$user_vars" + # Verify that the copy was successful + if [ $? -ne 0 ] + then + echo -e "\n\e[31mERROR: Failed to copy $src_vars to $user_vars.\e[0m" + echo "Usage: ./change_profile.sh " + exit 1 + fi +fi + +# Apply the new config +if [ -f "$user_cfg" ] +then + # Copy the new config to the user config + cp "$src_cfg" "$user_cfg" + # Verify that the copy was successful + if [ $? -ne 0 ] + then + echo -e "\n\e[31mERROR: Failed to copy $src_cfg to $user_cfg.\e[0m" + echo "Usage: ./change_profile.sh " + exit 1 + fi +fi + +# Check for the new profile marker in the user_vars +if [ -f "$user_vars" ] +then + # Search for the profile_pattern in the user_vars using grep + vars_profile=$(grep -oP "$profile_pattern" "$user_vars" | cut -d':' -f2) + # Verify that the profile marker was found + if [ -z "$vars_profile" ] + then + echo -e "\n\e[31mERROR: Profile marker not found in $user_vars.\e[0m" + echo "Usage: ./change_profile.sh " + exit 1 + fi + # Search for the profile_pattern in the src_vars using grep + src_profile=$(grep -oP "$profile_pattern" "$src_vars" | cut -d':' -f2) + # Verify that the profile marker was found + if [ -z "$src_profile" ] + then + echo -e "\n\e[31mERROR: Profile marker not found in $src_vars.\e[0m" + echo "Usage: ./change_profile.sh " + exit 1 + fi + # Check if the profile is already active + if [ "$vars_profile" != "$src_profile" ] + then + echo -e "\n\e[31mERROR: Failed to apply profile $1.\e[0m" + echo "Usage: ./change_profile.sh " + exit 1 + fi +fi + +# Check for the new profile marker in the user_cfg +if [ -f "$user_cfg" ] +then + # Search for the profile_pattern in the user_cfg using grep + cfg_profile=$(grep -oP "$profile_pattern" "$user_cfg" | cut -d':' -f2) + # Verify that the profile marker was found + if [ -z "$cfg_profile" ] + then + echo -e "\n\e[31mERROR: Profile marker not found in $user_cfg.\e[0m" + echo "Usage: ./change_profile.sh " + exit 1 + fi + # Search for the profile_pattern in the src_cfg using grep + src_profile=$(grep -oP "$profile_pattern" "$src_cfg" | cut -d':' -f2) + # Verify that the profile marker was found + if [ -z "$src_profile" ] + then + echo -e "\n\e[31mERROR: Profile marker not found in $src_cfg.\e[0m" + echo "Usage: ./change_profile.sh " + exit 1 + fi + # Check if the profile is already active + if [ "$cfg_profile" != "$src_profile" ] + then + echo -e "\n\e[31mERROR: Failed to apply profile $1.\e[0m" + echo "Usage: ./change_profile.sh " + exit 1 + fi +fi + +# Remove temp files + +# Check if src_vars is a temp file +if [ "${src_vars: -4}" == ".tmp" ] +then + # Remove the temp file + rm "$src_vars" + # Verify that the file was removed + if [ $? -ne 0 ] + then + echo -e "\n\e[31mERROR: Failed to remove $src_vars.\e[0m" + echo "Usage: ./change_profile.sh " + exit 1 + fi +fi + +# Check if src_cfg is a temp file +if [ "${src_cfg: -4}" == ".tmp" ] +then + # Remove the temp file + rm "$src_cfg" + # Verify that the file was removed + if [ $? -ne 0 ] + then + echo -e "\n\e[31mERROR: Failed to remove $src_cfg.\e[0m" + echo "Usage: ./change_profile.sh " + exit 1 + fi +fi + +# Success +echo -e "\n\e[32mSuccessfully applied profile $1.\e[0m" diff --git a/scripts/install.sh b/scripts/install.sh index b8e5085..99c8c53 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -1,35 +1,37 @@ #!/bin/bash + # Copyright (C) 2023 Chris Laprade (chris@rootiest.com) -# +# # This file is part of Hephaestus. -# +# # Hephaestus is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # Hephaestus is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with Hephaestus. If not, see . ##################################### ## Printcfg Install Script ## -## Version 3.8.1 2023-5-21 ## +## Version 4.0.0 2023-6-1 ## ##################################### # This script will download and install the printcfg package from GitHub. # Arguments: # $1: (optional) (default: default) +# $2: (optional) (default: master) #################################################################################################### # To install with the default profile open a terminal and run the following: -# curl https://raw.githubusercontent.com/rootiest/printcfg/master/scripts/install.sh | bash +# curl https://raw.githubusercontent.com/rootiest/printcfg/master/scripts/install.sh | bash # or to specify a profile: @@ -44,11 +46,15 @@ PKGLIST="git python3-pip bc" # Set the dev and repo name dev="rootiest" repo="printcfg" -# Define the klipper config file -config=~/printer_data/config +branch="master" +# Get home directory +home=$(eval echo ~$USER) +# Define the klipper config paths +printer_data=$home/printer_data +config=$printer_data/config # Define the printer.cfg and moonraker.conf files -printer=~/printer_data/config/printer.cfg -moonraker=~/printer_data/config/moonraker.conf +printer=$config/printer.cfg +moonraker=$config/moonraker.conf # Set the default profile default_src=default @@ -62,11 +68,16 @@ else then src="$1" fi + # Set the branch + if [ -n "$2" ] + then + branch="$2" + fi fi # Welcome message -echo "Welcome to the printcfg install script." -echo "This script will download and install the printcfg package from GitHub." +echo "Welcome to the $repo install script." +echo "This script will download and install the $repo package from GitHub." echo echo "Checking dependencies..." @@ -92,7 +103,7 @@ if [ -n "$need_git" ] || [ -n "$need_pip" ] || [ -n "$need_bc" ]; then else echo -e "\e[32mAll dependencies are installed.\e[0m" fi -echo "Installing printcfg..." +echo "Installing $repo..." # Check if the repo exists if ! git ls-remote https://github.com/"$dev"/"$repo" >/dev/null; then @@ -101,23 +112,23 @@ if ! git ls-remote https://github.com/"$dev"/"$repo" >/dev/null; then fi # Change to the home directory -cd ~ +cd $home # Check if printcfg is already installed -if [ -d ~/$repo ]; +if [ -d $home/$repo ]; then - echo -e "\e[33mprintcfg repo is already installed.\e[0m" - echo "Updating printcfg repo..." + echo -e "\e[33m$repo repo is already installed.\e[0m" + echo "Updating $repo repo..." # Change to the repo directory - cd ~/$repo + cd $home/$repo # Pull the latest changes git pull else - echo "Installing printcfg repo..." + echo "Installing $repo repo..." # Clone the repo git clone https://github.com/"$dev"/"$repo" # Check if the repo was cloned - if [ ! -d ~/$repo ]; then + if [ ! -d $home/$repo ]; then echo -e "\e[31mError: Repo not cloned.\e[0m" exit 1 else @@ -126,18 +137,80 @@ else fi # Change to the repo directory -cd ~/$repo +cd $home/$repo + +# Find the current branch +current_branch=$(git branch --show-current) + +# Check if the branch was provided +if [ -n "$2" ] +then + echo "Checking out branch $branch..." + # Check if the branch exists + if ! git ls-remote --heads + then + echo -e "\e[31mError: Branch $branch does not exist.\e[0m" + exit 1 + fi +else + echo "Staying on branch $current_branch..." + branch=$current_branch +fi + +# Check if the branch is already checked out +if [ "$current_branch" != "$branch" ]; then + git switch $branch + # Check if the branch was switched + if [ $? -ne 0 ]; then + echo -e "\e[31mError: Branch not switched.\e[0m" + exit 1 + else + echo -e "\e[32mBranch switched successfully.\e[0m" + pull_branch=true + fi +else + echo -e "\e[33mAlready on branch $branch.\e[0m" +fi + +# Pull the latest changes +if [ -n "$pull_branch" ]; then + echo "Pulling latest changes..." + git pull +fi ### Run any setup scripts ### # Install the dependencies +echo "Installing dependencies..." if [ -f requirements.txt ]; then - pip install -r requirements.txt + pip3 install -r requirements.txt + echo -e "\e[32mDependencies installed successfully.\e[0m" +else + echo -e "\e[33mNo dependencies to install.\e[0m" +fi + +# Check if the service is enabled +echo "Checking if the ${repo} service is enabled..." +if systemctl is-enabled "${repo}" >/dev/null 2>&1; then + echo "The ${repo} service is enabled." +else + echo "Installing the ${repo} service..." + echo "Acquiring root privileges..." + # Acquire root privileges + sudo -v > $allowlist + if grep -qFx "$repo" "$allowlist" + then + echo -e "\e[32m$repo service added to allowlist successfully.\e[0m" + else + echo -e "\e[31mError: $repo service not added to allowlist.\e[0m" + exit 1 + fi fi echo -e "\e[32mInstall complete.\e[0m" -echo +echo # Perform all checks to make sure printcfg is installed correctly -echo "Checking printcfg installation..." +echo "Checking $repo installation..." # Check if the repo exists -if [ ! -d ~/$repo ]; then +if [ ! -d $home/$repo ]; then echo -e "\e[31mError: Repo not cloned.\e[0m" exit 1 fi @@ -267,42 +382,42 @@ then fi # Check if printcfg is included in the printer.cfg file -if ! grep -qFx "[include printcfg/user_config.cfg]" "$printer" +if ! grep -qFx "$uconfig_pattern" "$printer" then - echo -e "\e[31mError: printcfg config not included in $printer\e[0m" + echo -e "\e[31mError: $repo config not included in $printer\e[0m" exit 1 fi # Check if the moonraker config contains printcfg config -if ! grep -qFx "[include printcfg/moonraker-printcfg.conf]" "$moonraker" +if ! grep -qFx "$new_moon" "$moonraker" then - echo -e "\e[31mError: printcfg config not included in $moonraker\e[0m" + echo -e "\e[31mError: $repo config not included in $moonraker\e[0m" exit 1 fi # Check if printcfg symlink exists if [ ! -L $config/$repo ] then - echo -e "\e[31mError: printcfg symlink not created.\e[0m" + echo -e "\e[31mError: $repo symlink not created.\e[0m" exit 1 fi # Check if user config exists -if [ ! -f ~/$repo/user_config.cfg ] +if [ ! -f $config/user_config.cfg ] then - echo -e "\e[31mError: printcfg user config not found.\e[0m" + echo -e "\e[31mError: $repo user config not found.\e[0m" exit 1 fi # Check if user profile exists -if [ ! -f ~/$repo/user_profile.cfg ] +if [ ! -f $config/user_profile.cfg ] then - echo -e "\e[31mError: printcfg user profile not found.\e[0m" + echo -e "\e[31mError: $repo user profile not found.\e[0m" exit 1 fi # Acknowledge that the installation checks passed -echo -e "\e[32mprintcfg installation checks passed.\e[0m" +echo -e "\e[32m$repo installation checks passed.\e[0m" echo # Success! @@ -313,15 +428,10 @@ echo # Perform setup checks echo "Performing Setup Checks..." echo -source ~/$repo/scripts/setup.sh $src -# Check if setup.out exists -if [ -f setup.out ] -then - cat setup.out -else - echo -e "\e[32mSetup checks passed.\e[0m" -fi +bash $home/$repo/scripts/setup.sh $src + +echo -e "\e[32mSetup checks passed.\e[0m" echo @@ -335,4 +445,3 @@ systemctl restart moonraker echo echo -e "\e[32mInstallation completed successfully.\e[0m" - diff --git a/scripts/log_logger.py b/scripts/log_logger.py new file mode 100644 index 0000000..8d666f4 --- /dev/null +++ b/scripts/log_logger.py @@ -0,0 +1,70 @@ +# Copyright (C) 2023 Chris Laprade (chris@rootiest.com) +# +# This file is part of printcfg. +# +# printcfg is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# printcfg is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with printcfg. If not, see . + +import sys +from watchdog.observers import Observer +from watchdog.events import FileSystemEventHandler + +class LogFileHandler(FileSystemEventHandler): + def __init__(self, watched_file, output_file): + self.watched_file = watched_file + self.output_file = output_file + self.previous_line = None + + def on_modified(self, event): + if event.src_path == self.watched_file: + try: + with open(self.watched_file, 'r') as f: + current_line = f.readline().strip() + log_index = current_line.find("log = ") + if log_index != -1: + log_text = current_line[log_index + len("log = "):] + if log_text != self.previous_line: + with open(self.output_file, 'a') as output: + output.write(log_text + '\n') + self.previous_line = log_text + except IOError as e: + print("IOError: " + e.strerror) + +# Example usage: +watched_file = 'variables.cfg' +output_file = 'printcfg.log' + +# Check for arguments: +if len(sys.argv) > 1: + if sys.argv[1] == '-h' or sys.argv[1] == '--help': + print('Usage: python3 log_logger.py ') + sys.exit(0) + else: + if len(sys.argv) > 2: + watched_file = sys.argv[1] + output_file = sys.argv[2] + + + +event_handler = LogFileHandler(watched_file, output_file) +observer = Observer() +observer.schedule(event_handler, path='.', recursive=False) +observer.start() + +try: + while True: + pass +except KeyboardInterrupt: + observer.stop() + +observer.join() diff --git a/scripts/patch.sh b/scripts/patch.sh new file mode 100644 index 0000000..db6a73d --- /dev/null +++ b/scripts/patch.sh @@ -0,0 +1,320 @@ +#!/bin/bash + +# Copyright (C) 2023 Chris Laprade (chris@rootiest.com) +# +# This file is part of printcfg. +# +# printcfg is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# printcfg is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with printcfg. If not, see . + +##################################### +## Printcfg Patch Script ## +## Version 4.0.0 2023-6-1 ## +##################################### + +# This script will apply version patches to the user profile and user config. +# Arguments: +# $1: (optional) (default: [unused]) + +#################################################################################################### + +# Example: +# ./patch.sh 4.0.0 +# This will force the user profile to be patched for the specified version. + +# Example: +# ./patch.sh +# This will check the user profile version and patch it if necessary. + +#################################################################################################### + +# Set the dev and repo name +dev="rootiest" +repo="printcfg" +branch="master" +# Get home directory +home=$(eval echo ~$USER) +# Define the klipper config file +config=$home/printer_data/config +# Define the printer.cfg and moonraker.conf files +printer=$home/printer_data/config/printer.cfg +moonraker=$home/printer_data/config/moonraker.conf +# Set the default profile +default_src=default +user_vars=$config/user_profile.cfg +old_user_vars=$config/$repo/user_profile.cfg +user_cfg=$config/user_config.cfg +old_user_cfg=$config/$repo/user_config.cfg +# Patterns to identify profile name and version +profile_pattern="# Profile:(.*)" +patch_pattern="# Patch:(.*)" +uconfig_pattern_old="[include $repo/user_config.cfg]" +uconfig_pattern_new="[include user_config.cfg]" +ver_patch="# Patch: *" + +# Check if any parameters were provided +if [ $# -eq 0 ] +then + # Get the user profile version + user_vars_version=$(grep -oP '(variable_version: ).*' $user_vars) + user_vars_version=${user_vars_version#variable_version: } +else + # Set the user profile version + if [ -n "$1" ] + then + user_vars_version=$1 + fi +fi + +echo "Checking user config path..." + +# Check that user config exists +if [ ! -f $user_cfg ] +then + # Check if old user config exists + if [ -f $old_user_cfg ] + then + echo -e "\e[31mUser config location is out of date.\e[0m" + mv $old_user_cfg $user_cfg + # Verify move was successful + if [ -f $user_cfg ] + then + echo "User config moved to $config/user_config.cfg" + else + echo -e "\e[31mUser config move failed.\e[0m" + exit 1 + fi + # Check if old include line exists in printer.cfg + echo "Checking printer.cfg include line..." + if grep -qFx "$uconfig_pattern_old" "$printer" + then + echo -e "\e[31mInclude line is out of date.\e[0m" + # Replace old include line with new include line + python3 $home/$repo/scripts/search_replace.py "$uconfig_pattern_old" "$uconfig_pattern_new" "$printer" + # Verify include line was added + if grep -qFx "$uconfig_pattern_new" "$printer" + then + echo "Include line updated." + # User config is up to date + echo -e "\e[32mUser config is now up to date.\e[0m" + else + echo -e "\e[31mInclude line update failed.\e[0m" + exit 1 + fi + else + if grep -qFx "$uconfig_pattern_new" "$printer" + then + echo -e "\e[32mUser config is up to date.\e[0m" + else + echo -e "\e[31mInclude line does not exist.\e[0m" + exit 1 + fi + fi + else + echo -e "\e[31mUser config does not exist.\e[0m" + exit 1 + fi +else + # User config is up to date + echo -e "\e[32mUser config path is up to date.\e[0m" +fi + +# Check user config profile marker +echo "Checking user config: profile..." + +# Search for the profile_pattern in the user_cfg using grep +config_profile=$(grep -oP "$profile_pattern" "$user_cfg" | cut -d':' -f2) + +if [ -n "$config_profile" ]; then + echo "Profile: $config_profile" +else + echo -e "\e[31mUser config profile marker not found.\e[0m" + exit 1 +fi + +# Check user config patch version marker +echo "Checking user config: version..." + +# Search for the patch pattern in the user_cfg +config_ver=$(grep -oP "$patch_pattern" "$user_cfg" | cut -d':' -f2) + +if [ -n "$config_ver" ]; then + # Extract the version number using sed + echo "Version: $config_ver" +else + echo -e "\e[31mUser config version marker not found.\e[0m" + exit 1 +fi + +# Check user profile profile marker +echo "Checking user profile: profile..." + +# Search for the profile_pattern in the user_vars using grep +vars_profile=$(grep -oP "$profile_pattern" "$user_vars" | cut -d':' -f2) + +if [ -n "$vars_profile" ]; then + echo "Profile: $vars_profile" +else + echo -e "\e[31mUser profile profile marker not found.\e[0m" + exit 1 +fi + +# Check user profile patch version marker +echo "Checking user profile: version..." + +# Search for the patch pattern in the user_vars +vars_ver=$(grep -oP "$patch_pattern" "$user_vars" | cut -d':' -f2) + +if [ -n "$vars_ver" ]; then + # Extract the version number using sed + echo "Version: $vars_ver" +else + echo -e "\e[31mUser profile version marker not found.\e[0m" + exit 1 +fi + +# Find the latest version in the patch_notes. +echo "Checking patch notes..." + +# Search for the patch pattern in the patch_notes +patch_notes="$home/$repo/profiles/$vars_profile/patch_notes.txt" + +# Read version from patch notes +highest_version=$(python3 $home/$repo/scripts/read_patch_notes.py "$patch_notes") + +# Print the highest version number +echo "Latest patch is: $highest_version" + +# Check if the user config version is the same as the highest version +if [ "$config_ver" = "$highest_version" ]; then + echo -e "\e[32mUser config is up to date.\e[0m" + update_config=False +else + echo -e "\e[31mUser config is out of date.\e[0m" + update_config=True +fi + +# Check if the user profile version is the same as the highest version + +if [ "$vars_ver" = "$highest_version" ]; then + echo -e "\e[32mUser profile is up to date.\e[0m" + update_profile=False +else + echo -e "\e[31mUser profile is out of date.\e[0m" + update_profile=True +fi + +if [ "$update_config" = "False" ] && [ "$update_profile" = "False" ]; then + echo -e "\e[32mUser config and profile are up to date.\e[0m" + echo -e "\e[32mNo action required.\e[0m" + exit 0 +else + # Search for patch files matching the user profile version + echo "Searching for patch files..." + vars_patch=$home/$repo/profiles/$vars_profile/patches/$highest_version/vars.patch + config_patch=$home/$repo/profiles/$config_profile/patches/$highest_version/config.patch + + # Check if the config needs to be updated + if [ "$update_config" = "True" ]; then + # Check if the patch file exists + if [ -f $config_patch ]; then + echo "Patch file found." + # Append the contents of the patch file to the user config + echo "Applying config patch file..." + cat $config_patch >> $user_cfg + echo "Config patch file applied." + # Update version number in user config + echo "Updating version number..." + # Replace the version number using sed + python3 $home/$repo/scripts/search_replace.py "$ver_patch" "$ver_patch$highest_version" "$user_cfg" + # Verify that the version number has been updated + if grep -qFx "$ver_patch$highest_version" "$user_cfg" + then + echo -e "\e[32mVersion number updated.\e[0m" + else + echo -e "\e[31mVersion number update failed.\e[0m" + exit 1 + fi + echo "Version number updated." + else + echo -e "\e[31mConfig patch file not found.\e[0m" + echo "Patch file: $config_patch" + exit 1 + fi + fi + + # Check if the profile needs to be updated + if [ "$update_profile" = "True" ]; then + # Check if the patch file exists + if [ -f $vars_patch ]; then + echo "Patch file found." + # Append the contents of the patch file to the user config + echo "Applying profile patch file..." + # Find the line containing '# End Custom Variables #' + vars_end=$(grep -n '# End Custom Variables #' $user_vars | cut -d':' -f1) + # Make sure the line number is not empty + if [ -z "$vars_end" ]; then + echo -e "\e[31mEnd of custom variables marker not found.\e[0m" + echo "Marker: # End Custom Variables #" + echo + echo "Using 'gcode:' instead." + vars_end=$(grep -n 'gcode:' $user_vars | cut -d':' -f1) + fi + # Add the patch before the line + sed -i "$vars_end r $vars_patch" $user_vars + # Add a newline after the patch + sed -i "$vars_end a \ " $user_vars + echo "Profile patch file applied." + # Update version number in user profile + echo "Updating version number..." + # Replace the version number using sed + python3 $home/$repo/scripts/search_replace.py "$ver_patch" "$ver_patch$highest_version" "$user_vars" + # Verify that the version number has been updated + if grep -qFx "$ver_patch$highest_version" "$user_vars" + then + echo -e "\e[32mVersion number updated.\e[0m" + else + echo -e "\e[31mVersion number update failed.\e[0m" + exit 1 + fi + else + echo -e "\e[31mProfile patch file not found.\e[0m" + echo "Patch file: $vars_patch" + exit 1 + fi + fi + + # Summarize results + echo + echo "Summary:" + if [ "$update_config" = "True" ]; then + echo -e "\e[32mUser config was successfully patched.\e[0m" + echo -e "Version: $highest_version" + else + echo -e "\e[32mUser config patch was not needed.\e[0m" + echo -e "Version: $config_ver" + fi + if [ "$update_profile" = "True" ]; then + echo -e "\e[32mUser profile was successfully patched.\e[0m" + echo -e "Version: $highest_version" + else + echo -e "\e[32mUser profile patch was not needed.\e[0m" + echo -e "Version: $vars_ver" + fi + + echo + echo -e "\e[32mPatching completed successfully.\e[0m" + exit 0 + +fi + diff --git a/scripts/read_patch_notes.py b/scripts/read_patch_notes.py new file mode 100644 index 0000000..d5a3b30 --- /dev/null +++ b/scripts/read_patch_notes.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2023 Chris Laprade (chris@rootiest.com) +# +# This file is part of printcfg. +# +# printcfg is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# printcfg is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with printcfg. If not, see . + +#!/usr/bin/env python3 + +# This script reads the patch notes file and returns the highest version number. + +import os +import sys +import re + +def find_highest_version(file_name): + highest_version = None + + with open(file_name, 'r') as file: + content = file.read() + + pattern = r'(\d+\.\d+\.\d+):' + versions = re.findall(pattern, content) + + for version in versions: + if highest_version is None or version > highest_version: + highest_version = version + + return highest_version + + +# Test the function +file_name = sys.argv[1] +highest_version = find_highest_version(file_name) +print(highest_version) diff --git a/scripts/remove_printcfg.sh b/scripts/remove_printcfg.sh new file mode 100644 index 0000000..eebf5ab --- /dev/null +++ b/scripts/remove_printcfg.sh @@ -0,0 +1,119 @@ +#!/bin/bash +# Copyright (C) 2023 Chris Laprade (chris@rootiest.com) +# +# This file is part of printcfg. +# +# printcfg is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# printcfg is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with printcfg. If not, see . + +# This script will remove printcfg from your system. + +# Set the dev and repo name +dev="rootiest" +repo="printcfg" +branch="master" +# Get home directory +home=$(eval echo ~$USER) +# Define the klipper config file +config=$home/printer_data/config +# Define the printer.cfg and moonraker.conf files +printer=$home/printer_data/config/printer.cfg +moonraker=$home/printer_data/config/moonraker.conf +# Set the default profile +default_src=default +user_vars=$config/user_profile.cfg +old_user_vars=$config/$repo/user_profile.cfg +user_cfg=$config/user_config.cfg +old_user_cfg=$config/$repo/user_config.cfg + +# Check if any parameters were provided +if [ "$1" ]; then + # No parameters were provided + # Check if the first parameter is 'force' + if [ "$1" != "force" ]; then + # Prompt the user to confirm + echo -e "\e[31mWARNING: This script will remove $repo from your system.\e[0m" + read -p "Are you sure you want to remove $repo? [y/N] " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + # Exit the script + exit 1 + fi +fi + +# Stop the printcfg service +sudo systemctl stop $repo.service + +# Verify that the printcfg service was stopped +if [ "$(systemctl is-active $repo.service)" = "active" ]; then + echo -e "\e[31mFailed to stop the printcfg service.\e[0m" + exit 1 +fi + +# Remove the printcfg service +sudo rm /etc/systemd/system/$repo.service + +# Verify that the printcfg service was removed +if [ -f /etc/systemd/system/$repo.service ]; then + echo -e "\e[31mFailed to remove the printcfg service.\e[0m" + exit 1 +fi + +# Remove the [include user_config.cfg] line from printer.cfg +include_line="[include user_config.cfg]" +replace_line="#[include user_config.cfg]" +python3 $home/$repo/scripts/search_replace.py $include_line $replace_line $printer + +# Remove the printcfg directory +sudo rm -r $home/$repo + +# Verify that the printcfg directory was removed +if [ -d $home/$repo ]; then + echo -e "\e[31mFailed to remove the printcfg directory.\e[0m" + exit 1 +fi + +# Remove the printcfg symlink from the klipper config directory +sudo rm $config/$repo + +# Verify that the printcfg symlink was removed +if [ -L $config/$repo ]; then + echo -e "\e[31mFailed to remove the printcfg symlink.\e[0m" + exit 1 +fi + +# Success +echo -e "\e[32mSuccessfully removed $repo.\e[0m" + + + + + + + + + + + + + + + +# Get the current script directory +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +# Remove the script directory +rm -r "$SCRIPT_DIR" + +# Remove the script file +rm "$0" \ No newline at end of file diff --git a/scripts/search_replace.py b/scripts/search_replace.py new file mode 100644 index 0000000..6364021 --- /dev/null +++ b/scripts/search_replace.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2023 Chris Laprade (chris@rootiest.com) +# +# This file is part of printcfg. +# +# printcfg is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# printcfg is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with printcfg. If not, see . + +#!/usr/bin/env python3 + +# This code searches for a string in a file and replaces the whole line containing the string with a different string. +# The search is case sensitive. +# It will add the line if it does not exist. +# It will overwrite the file with the new contents. +# The file must already exist. +# +# Arguments: +# search_text: The text to search for. +# replace_text: The text to replace the search_text with. +# file_name: The name of the file to search and replace. +# +# Returns: +# A status indicating whether the change was successful. +# +# Usage: +# python3 search_replace.py +# +# Example: +# python3 search_replace.py "version" "version: 1.0.0" "patch_notes.txt" + +import sys +import re +import logging + +logger: logging.Logger = logging.getLogger(__name__) + +# Set the logging level +logger.setLevel(logging.DEBUG) +formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s") +handler = logging.StreamHandler(sys.stdout) +handler.setFormatter(formatter) +logger.addHandler(handler) + + +def search_and_replace(search_text: str, replace_text: str, file_name: str) -> bool: + """Searches for the line containing the search_text and replaces the whole line with the replace_text and saves the updated file over the original. + + Args: + search_text: The text to search for. + replace_text: The text to replace the search_text with. + file_name: The name of the file to search and replace. + + Returns: + A status indicating whether the change was successful. + """ + + # Log the input + logger.debug( + "search_and_replace() called with: search_text=%s, replace_text=%s, file_name=%s", + search_text, + replace_text, + file_name, + ) + + # Make sure the inputs are valid + if search_text is None or replace_text is None or file_name is None: + logger.error( + "search_and_replace() failed due to invalid input: search_text=%s, replace_text=%s, file_name=%s", + search_text, + replace_text, + file_name, + ) + return False + + # Open the file + logger.debug("search_and_replace() opened the file %s", file_name) + with open(file_name, "r") as f: + lines = f.readlines() + + # Search the file for the search_text + found = False + for i, line in enumerate(lines): + if re.search(search_text, line): + lines[i] = replace_text + "\n" + found = True + break + + # If the search_text wasn't found, insert the replace_text at the top + if not found: + lines.insert(0, replace_text + "\n") + + # Write the file + logger.debug("search_and_replace() wrote the file %s", file_name) + with open(file_name, "w") as f: + f.writelines(lines) + + return True + return found + + +# Check the number of arguments +if len(sys.argv) != 4: + # Print the usage + print("Usage:") + print(" python3 search_replace.py ") + print("Example:") + print(' python3 search_replace.py "version" "version: 1.0.0" "patch_notes.txt"') + sys.exit(1) + +search_text = sys.argv[1] +replace_text = sys.argv[2] +file_name = sys.argv[3] + +status = search_and_replace(search_text, replace_text, file_name) +if status: + print("The change was successful.") +else: + print("The text to search for was not found.") diff --git a/scripts/setup.sh b/scripts/setup.sh index 3f8d014..4e690e2 100644 --- a/scripts/setup.sh +++ b/scripts/setup.sh @@ -1,24 +1,25 @@ #!/bin/bash + # Copyright (C) 2023 Chris Laprade (chris@rootiest.com) -# +# # This file is part of printcfg. -# +# # printcfg is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # printcfg is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with printcfg. If not, see . ##################################### ## Printcfg Setup Script ## -## Version 3.8.1 2023-5-21 ## +## Version 4.0.0 2023-6-1 ## ##################################### # This script will check the user profile and update it if necessary. @@ -41,11 +42,14 @@ # Set the dev and repo name dev="rootiest" repo="printcfg" +branch="master" +# Get home directory +home=$(eval echo ~$USER) # Define the klipper config file -config=~/printer_data/config +config=$home/printer_data/config # Define the printer.cfg and moonraker.conf files -printer=~/printer_data/config/printer.cfg -moonraker=~/printer_data/config/moonraker.conf +printer=$home/printer_data/config/printer.cfg +moonraker=$home/printer_data/config/moonraker.conf # Set the default profile default_src=default user_vars=$config/user_profile.cfg @@ -67,6 +71,26 @@ else fi fi +echo "Checking $repo executable..." +# Check if bin exists +if [ ! -f /usr/local/bin/$repo ] +then + echo "Creating $repo bin..." + sudo ln -s $home/$repo/src/$repo.py /usr/local/bin/$repo + sudo chmod +x /usr/local/bin/$repo + echo -e "\e[32m$repo bin created successfully.\e[0m" +else + # Check if bin is executable + if [ ! -x /usr/local/bin/$repo ] + then + echo "Making $repo bin executable..." + sudo chmod +x /usr/local/bin/$repo + echo -e "\e[32m$repo bin made executable.\e[0m" + else + echo -e "\e[32m$repo bin is up to date.\e[0m" + fi +fi + echo "Checking user config..." # Check that user config exists @@ -87,11 +111,11 @@ then fi # Check if old include line exists in printer.cfg echo "Checking printer.cfg include line..." - if grep -qFx "[include printcfg/user_config.cfg]" "$printer" + if grep -qFx "[include $repo/user_config.cfg]" "$printer" then echo -e "\e[31mInclude line is out of date.\e[0m" # Remove old include line - sed -i '/\[include printcfg\/user_config.cfg\]/d' "$printer" + sed -i '/\[include $repo\/user_config.cfg\]/d' "$printer" # Add new include line sed -i '1s/^/[include user_config.cfg]\n/' "$printer" # Verify include line was added @@ -122,6 +146,7 @@ else echo -e "\e[32mUser config is up to date.\e[0m" fi +echo echo "Checking user profile..." # Check that user profile exists @@ -181,32 +206,44 @@ if [ "$user_vars_version" != "$src_vars_version" ]; then else echo echo -e "\e[31mUser profile is not up to date.\e[0m" + echo "User version: $user_vars_version" + echo "Source version: $src_vars_version" echo echo -e "\033[1;31mVersion mismatch: [$user_vars]\e[0m" echo - echo "To force an update, run setup.sh with the profile you want to use and the word 'force' as arguments." - echo "For example, to force an update for the default profile, run the following command:" - echo " ~/$repo/scripts/setup.sh default force" - echo - echo -e "\033[4;31mNOTE: Forcing the update will overwrite any changes you have made to the user profile.\e[0m" - echo -e "\e[33mTo avoid this: please update the user profile manually following the patch notes.\e[0m" + echo "Attempting to patch user profile..." echo - echo -e "\e[31mUser profile is not up to date.\e[0m" - echo "User version: $user_vars_version" - echo "Source version: $src_vars_version" - echo - echo -e "\e[31mPlease update the user profile.\e[0m" - if [ -f $src_path/patch_notes.txt ]; then echo -e "\e[31mPatch notes:" cat $src_path/patch_notes.txt echo -e "\e[0m" fi - echo -e "\033[2;101mSetup checks failed.\e[0m" echo + bash $home/$repo/scripts/patch.sh exit 1 fi else echo -e "\e[32mUser profile is up to date.\e[0m" echo "User version: $user_vars_version" fi + +# Check that printcfg service is enabled +echo +echo "Checking $repo service..." +if systemctl is-enabled $repo.service | grep -q "enabled" +then + # Check if printcfg service is running + if systemctl is-active $repo.service | grep -q "active" + then + echo -e "\e[32m$repo service is active.\e[0m" + else + echo -e "\e[31m$repo service is not running.\e[0m" + exit 1 + fi +else + echo -e "\e[31m$repo service is not enabled.\e[0m" + exit 1 +fi + +echo +exit 0 \ No newline at end of file diff --git a/src/gen_service.py b/src/gen_service.py new file mode 100644 index 0000000..aa0cbcc --- /dev/null +++ b/src/gen_service.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2023 Chris Laprade (chris@rootiest.com) +# +# This file is part of printcfg. +# +# printcfg is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# printcfg is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with printcfg. If not, see . + +# This script generates a service file for printcfg. + +#!/usr/bin/env python3 +import os +import sys +import subprocess + +if len(sys.argv) < 3: + USER = os.environ["USER"] + GROUP = os.environ["USER"] + HOME= os.path.expanduser('~') +else: + USER = sys.argv[1] + GROUP = sys.argv[1] + HOME = sys.argv[2] + +# Service name and configuration file +SERVICE_NAME = "printcfg" +SERVICE_FILE = f"/etc/systemd/system/{SERVICE_NAME}.service" +SERVICE_PATH = f"{HOME}/{SERVICE_NAME}" + +# Path to the Python script +PYTHON_SCRIPT = f"{SERVICE_PATH}/src/{SERVICE_NAME}.py" +PYTHON_EXECUTABLE = sys.executable + +if len(sys.argv) < 2 and len(sys.argv) > 0: + MODE = sys.argv[1] +elif len(sys.argv) < 0: + print("Please provide the 'install' argument to install the service.") +else: + if sys.argv[3] == "install": + if not PYTHON_SCRIPT: + print("Please provide the path to the Python script as an argument.") + sys.exit(1) + + # Create the service file + service_content = f"""\ + [Unit] + Description=Print Configuration Service + Requires=klipper.service + After=klipper.service + + [Service] + Mode=oneshot + User={USER} + Group={GROUP} + RemainAfterExit=yes + ExecStart={PYTHON_EXECUTABLE} {PYTHON_SCRIPT} + WorkingDirectory={os.path.dirname(SERVICE_PATH)} + TimeoutStartSec=0 + + [Install] + WantedBy=default.target + """ + + print("Installing service...") + print(f"Service file: {SERVICE_FILE}") + print(f"Python script: {PYTHON_SCRIPT}") + print(f"Python executable: {PYTHON_EXECUTABLE}") + print(f"Working directory: {os.path.dirname(SERVICE_PATH)}") + + os.makedirs(os.path.dirname(SERVICE_FILE), exist_ok=True) + with open(SERVICE_FILE, "w") as service: + service.write(service_content) + + # Set the appropriate permissions for the service configuration file + os.chmod(SERVICE_FILE, 0o644) + + # Reload systemd to recognize the new service + os.system("systemctl daemon-reload") + + # Enable and start the service + os.system(f"systemctl enable {SERVICE_NAME}") + os.system(f"systemctl start {SERVICE_NAME}") + + # Check the status of the service + os.system(f"systemctl status {SERVICE_NAME}") + + # Symbolic link to the executable + os.symlink(PYTHON_SCRIPT, f"/usr/local/bin/{SERVICE_NAME}") + # Set the appropriate permissions for the executable + os.chmod(f"/usr/local/bin/{SERVICE_NAME}", 0o755) + + else: + print("Please provide the 'install' argument to install the service.") + sys.exit(1) \ No newline at end of file diff --git a/moonraker-printcfg.conf b/src/mooncfg.conf similarity index 80% rename from moonraker-printcfg.conf rename to src/mooncfg.conf index 8532857..37c523f 100644 --- a/moonraker-printcfg.conf +++ b/src/mooncfg.conf @@ -1,6 +1,6 @@ ##################################### ## Printcfg Moonraker ## -## Version 3.8.1 2023-5-21 ## +## Version 4.0.0 2023-6-1 ## ##################################### ## Manage updates for Rootiest printcfg Suite for Klipper @@ -10,8 +10,8 @@ channel: dev primary_branch: master path: ~/printcfg origin: https://github.com/rootiest/printcfg.git -is_system_service: False +is_system_service: True install_script: scripts/install.sh -managed_services: klipper +managed_services: printcfg klipper info_tags: desc=Rootiest printcfg Suite for Klipper \ No newline at end of file diff --git a/src/printcfg.py b/src/printcfg.py new file mode 100755 index 0000000..b5f070e --- /dev/null +++ b/src/printcfg.py @@ -0,0 +1,259 @@ +#!/usr/bin/env python3 +# Copyright (C) 2023 Chris Laprade (chris@rootiest.com) +# +# This file is part of printcfg. +# +# printcfg is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# printcfg is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with printcfg. If not, see . + +# This is the printcfg process that runs in the background. +# It also manages the printcfg service. +# Usage: python3 printcfg.py [mode] +# Modes: +# default: Run the script normally (default) +# install: Install the printcfg service +# change: Change the printcfg profile +# remove: Remove the printcfg service +# update: Update printcfg + +#!/usr/bin/env python3 + +import os +import sys +import getpass +import subprocess +import logging + +logger: logging.Logger = logging.getLogger(__name__) + +# Set the repo name +REPO = "printcfg" + +# Get the current user name +current_user = getpass.getuser() +user_home = os.path.expanduser("~") +profile_path = f"{user_home}/printer_data/user_profile.cfg" +setup_script = f"{user_home}/printcfg/scripts/setup.sh" + +# Set the logfile +logfile = f"{user_home}/printcfg/logs/printcfg.log" + +# Check if the logfile exists +if not os.path.exists(f"{user_home}/printcfg/logs/"): + # Create the log directory + os.mkdir(f"{user_home}/printcfg/logs/") + # Create the logfile + with open(logfile, "w") as file: + pass + +# Set the logging level +logger.setLevel(logging.DEBUG) +formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s") +handler = logging.FileHandler(logfile) +handler.setFormatter(formatter) +logger.addHandler(handler) + + +def find_profile(path): + logger.debug("Searching for profile name in file: {}".format(path)) + # Find the profile name (Eg: '# Profile: default' = 'default') + with open(path, "r") as file: + for line in file: + if line.startswith("# Profile: "): + logger.debug("Found profile name: {}".format(line[11:].strip())) + # Return the profile name + return line[11:].strip() + + # If no profile was found, raise an error + logger.error("Profile not found in file: {}".format(path)) + raise ValueError("Profile not found in file: {}".format(path)) + + +def normal_ops(): + logger.info("Starting normal operations...") + try: + # Run the shell script at startup + subprocess.Popen(["/bin/bash", setup_script]) + logger.info("Startup script complete.") + except Exception as e: + # Log the error + logger.error("Error running startup script: {}".format(str(e))) + # Exit with error + exit(1) + # Exit successfully + logger.info("Startup script complete, exiting.") + exit(0) + + +def generate_service(): + logger.info("Generating service...") + # Define the path to the second script + script_dir = f"{user_home}/{REPO}/" + logger.debug("Script directory: {}".format(script_dir)) + mode = sys.argv[1] + logger.debug("Mode: {}".format(mode)) + # Define the path to the second script + script_path = f"{script_dir}/src/gen_service.py" + logger.debug("Script path: {}".format(script_path)) + # Check if the second script exists + if not os.path.isfile(script_path): + print(f"Error: The script '{script_path}' does not exist.") + logger.error("Error: The script '{}' does not exist.".format(script_path)) + return + # Start the second script as root with the current user name as the first argument + command = ["sudo", "python3", script_path, current_user, user_home, mode] + logger.debug("Executing command: {}".format(command)) + print(f"Executing command: {command}") + try: + result = subprocess.run(command, capture_output=True) + except subprocess.CalledProcessError as e: + print(f"Error: The subprocess returned an error.") + print(e.stderr) + logger.error("Error: The subprocess returned an error: {}".format(e.stderr)) + return + logger.debug("Command output: {}".format(result.stdout.decode("utf-8"))) + if result.returncode != 0: + print(f"Error: The command '{command}' failed with code {result.returncode}.") + logger.error("Error: The command '{}' failed with code {}.".format(command, result.returncode)) + print(f"Output from command: {result.stdout.decode('utf-8')}") + print(f"Error from command: {result.stderr.decode('utf-8')}") + return + # Exit successfully + logger.info("Service generated successfully.") + exit(0) + + +def change_profile(profile): + # Define the path to the second script + script_path = f"{user_home}/{REPO}/scripts/change_profile.sh" + logger.debug("Script path: {}".format(script_path)) + # Check if the second script exists + if not os.path.isfile(script_path): + print(f"Error: The script '{script_path}' does not exist.") + logger.error("Error: The script '{}' does not exist.".format(script_path)) + return + # Start the change profile script + command = ["bash", script_path, profile] + logger.debug("Executing command: {}".format(command)) + try: + subprocess.run(command, check=True) + except subprocess.CalledProcessError as e: + print("Error: The subprocess returned an error.") + print(e.stderr) + logger.error("Error: The subprocess returned an error: {}".format(e.stderr)) + # Exit successfully + logger.info("Profile changed successfully.") + exit(0) + + +def update_printcfg(): + # Define the path to the second script + script_path = f"{user_home}/{REPO}/scripts/install.sh" + # Check if the second script exists + if not os.path.isfile(script_path): + print(f"Error: The script '{script_path}' does not exist.") + return + # Find the current profile + profile = find_profile(profile_path) + # Start the update script + command = ["bash", script_path, profile] + logger.debug("Executing command: {}".format(command)) + try: + subprocess.run(command) + except subprocess.CalledProcessError as e: + print("Error: The subprocess returned an error.") + print(e.stderr) + logger.error("Error: The subprocess returned an error: {}".format(e.stderr)) + # Exit successfully + logger.info("Update complete.") + exit(0) + + +def remove_printcfg(): + # Define the path to the second script + script_path = f"{user_home}/{REPO}/scripts/remove_{REPO}.sh" + logger.debug("Script path: {}".format(script_path)) + # Check if the second script exists + if not os.path.isfile(script_path): + print(f"Error: The script '{script_path}' does not exist.") + logger.error("Error: The script '{}' does not exist.".format(script_path)) + return + # Start the second script as root with the current user name as the first argument + command = ["bash", script_path] + logger.debug("Executing command: {}".format(command)) + try: + subprocess.run(command) + except subprocess.CalledProcessError as e: + print("Error: The subprocess returned an error.") + print(e.stderr) + logger.error("Error: The subprocess returned an error: {}".format(e.stderr)) + # Exit successfully + logger.info("Printcfg removed successfully.") + exit(0) + + +if __name__ == "__main__": + # Check if there are any arguments + if len(sys.argv) < 2: + logger.info("No arguments provided, running normal operations.") + normal_ops() + sys.exit(1) + # Check the argument + if sys.argv[1] not in ["install", "change", "remove", "update", "default"]: + print( + "Error: The argument must be either install, change, remove, update, or default." + ) + logger.error("Error: The argument must be either install, change, remove, update, or default.") + sys.exit(1) + # If the argument is 'install' start the script as root + if sys.argv[1] == "install": + logger.info("Running install operations.") + generate_service() + # If the argument is 'change' check for a second argument + elif sys.argv[1] == "change": + if len(sys.argv) != 3: + print("Error: The change script requires two arguments.") + print(f"Usage: python3 {REPO}.py change ") + logger.error("Error: The change script requires two arguments.") + sys.exit(1) + else: + # Check if the profile exists + profile = sys.argv[2] + logger.info("Running change operations.") + profile_path = f"{user_home}/{REPO}/profiles/{profile}" + logger.debug("Profile path: {}".format(profile_path)) + print(f"Changing to profile '{profile}'") + # If the profile is 'backup' then skip the check + if profile == "backup": + logger.info("Changing to backup profile.") + change_profile(profile) + else: + # If the profile path does not exist, exit + if not os.path.isdir(profile_path): + print(f"Error: The profile '{profile}' does not exist.") + logger.error("Error: The profile '{}' does not exist.".format(profile)) + sys.exit(1) + else: + logger.info("Changing to profile '{}'.".format(profile)) + change_profile(profile) + # If the argument is 'remove' + elif sys.argv[1] == "remove": + logger.info("Running remove operations.") + remove_printcfg() + elif sys.argv[1] == "update": + logger.info("Running update operations.") + update_printcfg() + + else: + logger.info("Running normal operations.") + normal_ops() diff --git a/src/requirements.txt b/src/requirements.txt index e69de29..b2ef71f 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -0,0 +1,4 @@ +python-apt==0.7.8 +python-dateutil==2.8.2 +requests==2.30.0 +watchdog==3.0.0 \ No newline at end of file