diff --git a/config/CreatBot_D1000/base.cfg b/config/CreatBot_D1000/base.cfg index 312c5a214..7d456b0e1 100644 --- a/config/CreatBot_D1000/base.cfg +++ b/config/CreatBot_D1000/base.cfg @@ -378,7 +378,7 @@ gcode: {% else %} PAUSE SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=change_runout VALUE='"T0"' - RESPOND TYPE=error MSG='{"Noting! extruder filament has been run out."}' + RESPOND TYPE=error MSG='{"Noting! Left extruder filament has been run out."}' {% endif %} [gcode_macro T1] @@ -405,7 +405,7 @@ gcode: {% else %} PAUSE SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=change_runout VALUE='"T1"' - RESPOND TYPE=error MSG='{"Noting! extruder1 filament has been run out."}' + RESPOND TYPE=error MSG='{"Noting! Right extruder filament has been run out."}' {% endif %} [gcode_macro PROBE_SERVO_OPEN] @@ -458,6 +458,10 @@ gcode: G92 E0 M117 Printing start... +[gcode_macro PRINT_START] +gcode: + START_PRINT + [gcode_macro END_PRINT] gcode: M400 @@ -472,6 +476,10 @@ gcode: G0 X590 Y590 F3600 # BED_MESH_CLEAR +[gcode_macro PRINT_END] +gcode: + END_PRINT + [gcode_macro LOAD_FILAMENT] variable_load_distance: 120 variable_purge_distance: 25 @@ -501,24 +509,6 @@ gcode: G1 E-{unload_distance} F{max_velocity} # fast-unload RESTORE_GCODE_STATE NAME=unload_state -[gcode_macro SET_X_OFFSET] -gcode: - {% set svv = printer.save_variables.variables %} - {% set dual_x_offset=params.S|default(-60)|float %} - SAVE_VARIABLE VARIABLE=dual_x_offset VALUE={dual_x_offset} - -[gcode_macro SET_Y_OFFSET] -gcode: - {% set svv = printer.save_variables.variables %} - {% set dual_y_offset=params.S|default(0)|float %} - SAVE_VARIABLE VARIABLE=dual_y_offset VALUE={dual_y_offset} - -[gcode_macro SET_Z_OFFSET] -gcode: - {% set svv = printer.save_variables.variables %} - {% set dual_z_offset=params.S|default(0)|float %} - SAVE_VARIABLE VARIABLE=dual_z_offset VALUE={dual_z_offset} - [gcode_macro _ACTIVATE_DEFAULT_EXTRUDER] gcode: {% if printer.toolhead.extruder == 'extruder' %} @@ -667,13 +657,13 @@ gcode: [gcode_macro _RESUME_EXTRUDER] gcode: {% set client = printer['gcode_macro RESUME']|default({}) %} - {% set autoshift_on = params.AUTOSHIFT|default(False) %} + {% set autoshift_on = params.AUTOSHIFT|default(False)|lower %} {% set toolchange = client.change_runout|lower|default("") %} {% set extruder_filament = client.filament_state.extruder %} {% set extruder1_filament = client.filament_state.extruder1 %} {% set resume_extruder = client.resume_extruder|default("extruder") %} - {% if autoshift_on %} + {% if autoshift_on == 'true' %} {% if extruder_filament and extruder1_filament %} {% if toolchange == "t0" %} {% set resume_extruder = "extruder" %} @@ -711,8 +701,10 @@ gcode: {'index': 1, 'name': 'last_extruder1_temp'}] %} {% set temperature = "last_extruder_temp" if printer.toolhead.extruder == "extruder" else "last_extruder1_temp" %} {% set value = printer["gcode_macro RESUME"][temperature].temp %} - RESPOND TYPE=echo MSG='{"Restoring \"%s\" temperature to %3.1f\u00B0C, this may take some time" % - (printer.toolhead.extruder, value)}' + {% if printer[printer.toolhead.extruder].temperature < value-3 %} + {% set msg = "Left" if printer.toolhead.extruder == "extruder" else "Right" %} + RESPOND TYPE=echo MSG='{"Restoring %s extruder temperature, this may take some time." % msg}' + {% endif %} {% for info in extruder_info %} {% set variable = printer["gcode_macro RESUME"][info.name] %} {% if variable.restore %} @@ -732,10 +724,40 @@ gcode: [gcode_macro _USER_CANCEL] gcode: - G91 - G1 Z30 F600 ; lift nozzle + {% if 'z' in printer.toolhead.homed_axes %} + G91 + G1 Z30 F600 ; lift nozzle + {% endif %} M84 +[gcode_macro _CLIENT_EXTRUDE] +description: Extrudes, if the extruder is hot enough +gcode: + ##### get user parameters or use default ##### + {% set client = printer['gcode_macro _CLIENT_VARIABLE']|default({}) %} + {% set use_fw_retract = (client.use_fw_retract|default(false)|lower == 'true') and (printer.firmware_retraction is defined) %} + {% set length = params.LENGTH|default(client.unretract)|default(1.0)|float %} + {% set speed = params.SPEED|default(client.speed_unretract)|default(35) %} + {% set absolute_extrude = printer.gcode_move.absolute_extrude %} + ##### end of definitions ##### + {% if printer.toolhead.extruder != '' %} + {% if printer[printer.toolhead.extruder].can_extrude %} + {% if use_fw_retract %} + {% if length < 0 %} + G10 + {% else %} + G11 + {% endif %} + {% else %} + M83 + G1 E{length} F{(speed|float|abs) * 60} + {% if absolute_extrude %} + M82 + {% endif %} + {% endif %} + {% endif %} + {% endif %} + [gcode_macro RESUME] description: Resume the actual running print rename_existing: RESUME_BASE @@ -745,10 +767,10 @@ variable_restore_idle_timeout: 0 variable_idle_state: False variable_filament_state: "" variable_change_runout: "" -variable_autoshift: False variable_resume_extruder: "" gcode: ##### get user parameters or use default ##### + {% set autoshift = printer.save_variables.variables.auto_change_nozzle|default(False) %} {% set client = printer['gcode_macro _CLIENT_VARIABLE']|default({}) %} {% set do_resume = False %} {% set runout = True %} @@ -768,16 +790,10 @@ gcode: {% set do_resume = True %} {% elif can_extrude %} {% set do_resume = True %} - {% else %} - RESPOND TYPE=error MSG='{"Resume aborted !!! \"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder}' - {% set _d = prompt_txt.append("\"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder) %} {% endif %} #### Printer comming out of regular PAUSE state #### {% elif can_extrude %} {% set do_resume = True %} - {% else %} - RESPOND TYPE=error MSG='{"Resume aborted !!! \"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder}' - {% set _d = prompt_txt.append("\"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder) %} {% endif %} _ACT_RESUME DO_RESUME={do_resume} @@ -799,17 +815,17 @@ gcode: _CLIENT_EXTRUDE RESUME_BASE VELOCITY={params.VELOCITY|default(sp_move)} SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=change_runout VALUE="None" - SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=autoshift VALUE="False" {% else %} - {% set _d = prompt_txt.append("\"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder) %} + {% set msg = "Left" if printer.toolhead.extruder == "extruder" else "Right" %} + {% set _d = prompt_txt.append("%s extruder not hot enough, will reheat and continue." % msg) %} {% endif %} {% else %} - RESPOND TYPE=error MSG='{"Resume aborted !!! \"%s\" detects no filament, please load filament and press RESUME" % printer.toolhead.extruder}' - {% set _d = prompt_txt.append("\"%s\" detects no filament, please load filament and press RESUME" % printer.toolhead.extruder) %} + {% set msg = "Left" if printer.toolhead.extruder == "extruder" else "Right" %} + {% set _d = prompt_txt.append("%s extruder detects no filament, please load filament and continue." % msg) %} {% endif %} ##### Generate User Information box in case of abort ##### {% if not (filament_state and do_resume) %} - RESPOND TYPE=command MSG="action:prompt_begin RESUME aborted !!!" + RESPOND TYPE=command MSG="action:prompt_begin RESUME ABORTED !" {% for element in prompt_txt %} RESPOND TYPE=command MSG='{"action:prompt_text %s" % element}' {% endfor %} @@ -860,14 +876,14 @@ gcode: {% if not filament_state %} PAUSE {% if autoshift_extruder %} - SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=autoshift VALUE=True {% if printer["gcode_macro RESUME"].filament_state[target_extruder] %} RESUME {% else %} RESPOND TYPE=error MSG='{"Noting! All extruders filament has been run out."}' {% endif %} {% else %} - RESPOND TYPE=error MSG='{"Noting! \"%s\" filament has been run out." % printer.toolhead.extruder}' + {% set msg = "Left" if printer.toolhead.extruder == "extruder" else "Right" %} + RESPOND TYPE=error MSG='{"Noting! %s extruder filament has been run out." % msg}' {% endif %} {% endif %} diff --git a/config/CreatBot_D1000_V0/base.cfg b/config/CreatBot_D1000_V0/base.cfg index a7f53925c..22e05218d 100644 --- a/config/CreatBot_D1000_V0/base.cfg +++ b/config/CreatBot_D1000_V0/base.cfg @@ -314,7 +314,7 @@ gcode: {% else %} PAUSE SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=change_runout VALUE='"T0"' - RESPOND TYPE=error MSG='{"Noting! extruder filament has been run out."}' + RESPOND TYPE=error MSG='{"Noting! Left extruder filament has been run out."}' {% endif %} [gcode_macro T1] @@ -341,7 +341,7 @@ gcode: {% else %} PAUSE SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=change_runout VALUE='"T1"' - RESPOND TYPE=error MSG='{"Noting! extruder1 filament has been run out."}' + RESPOND TYPE=error MSG='{"Noting! Right extruder filament has been run out."}' {% endif %} [gcode_macro PROBE_SERVO_OPEN] @@ -394,6 +394,10 @@ gcode: G92 E0 M117 Printing start... +[gcode_macro PRINT_START] +gcode: + START_PRINT + [gcode_macro END_PRINT] gcode: M400 @@ -408,6 +412,10 @@ gcode: G0 X590 Y590 F3600 # BED_MESH_CLEAR +[gcode_macro PRINT_END] +gcode: + END_PRINT + [gcode_macro LOAD_FILAMENT] variable_load_distance: 120 variable_purge_distance: 25 @@ -437,24 +445,6 @@ gcode: G1 E-{unload_distance} F{max_velocity} # fast-unload RESTORE_GCODE_STATE NAME=unload_state -[gcode_macro SET_X_OFFSET] -gcode: - {% set svv = printer.save_variables.variables %} - {% set dual_x_offset=params.S|default(-60)|float %} - SAVE_VARIABLE VARIABLE=dual_x_offset VALUE={dual_x_offset} - -[gcode_macro SET_Y_OFFSET] -gcode: - {% set svv = printer.save_variables.variables %} - {% set dual_y_offset=params.S|default(0)|float %} - SAVE_VARIABLE VARIABLE=dual_y_offset VALUE={dual_y_offset} - -[gcode_macro SET_Z_OFFSET] -gcode: - {% set svv = printer.save_variables.variables %} - {% set dual_z_offset=params.S|default(0)|float %} - SAVE_VARIABLE VARIABLE=dual_z_offset VALUE={dual_z_offset} - [gcode_macro _ACTIVATE_DEFAULT_EXTRUDER] gcode: {% if printer.toolhead.extruder == 'extruder' %} @@ -603,13 +593,13 @@ gcode: [gcode_macro _RESUME_EXTRUDER] gcode: {% set client = printer['gcode_macro RESUME']|default({}) %} - {% set autoshift_on = params.AUTOSHIFT|default(False) %} + {% set autoshift_on = params.AUTOSHIFT|default(False)|lower %} {% set toolchange = client.change_runout|lower|default("") %} {% set extruder_filament = client.filament_state.extruder %} {% set extruder1_filament = client.filament_state.extruder1 %} {% set resume_extruder = client.resume_extruder|default("extruder") %} - {% if autoshift_on %} + {% if autoshift_on == 'true' %} {% if extruder_filament and extruder1_filament %} {% if toolchange == "t0" %} {% set resume_extruder = "extruder" %} @@ -647,8 +637,10 @@ gcode: {'index': 1, 'name': 'last_extruder1_temp'}] %} {% set temperature = "last_extruder_temp" if printer.toolhead.extruder == "extruder" else "last_extruder1_temp" %} {% set value = printer["gcode_macro RESUME"][temperature].temp %} - RESPOND TYPE=echo MSG='{"Restoring \"%s\" temperature to %3.1f\u00B0C, this may take some time" % - (printer.toolhead.extruder, value)}' + {% if printer[printer.toolhead.extruder].temperature < value-3 %} + {% set msg = "Left" if printer.toolhead.extruder == "extruder" else "Right" %} + RESPOND TYPE=echo MSG='{"Restoring %s extruder temperature, this may take some time." % msg}' + {% endif %} {% for info in extruder_info %} {% set variable = printer["gcode_macro RESUME"][info.name] %} {% if variable.restore %} @@ -668,10 +660,40 @@ gcode: [gcode_macro _USER_CANCEL] gcode: - G91 - G1 Z30 F600 ; lift nozzle + {% if 'z' in printer.toolhead.homed_axes %} + G91 + G1 Z30 F600 ; lift nozzle + {% endif %} M84 +[gcode_macro _CLIENT_EXTRUDE] +description: Extrudes, if the extruder is hot enough +gcode: + ##### get user parameters or use default ##### + {% set client = printer['gcode_macro _CLIENT_VARIABLE']|default({}) %} + {% set use_fw_retract = (client.use_fw_retract|default(false)|lower == 'true') and (printer.firmware_retraction is defined) %} + {% set length = params.LENGTH|default(client.unretract)|default(1.0)|float %} + {% set speed = params.SPEED|default(client.speed_unretract)|default(35) %} + {% set absolute_extrude = printer.gcode_move.absolute_extrude %} + ##### end of definitions ##### + {% if printer.toolhead.extruder != '' %} + {% if printer[printer.toolhead.extruder].can_extrude %} + {% if use_fw_retract %} + {% if length < 0 %} + G10 + {% else %} + G11 + {% endif %} + {% else %} + M83 + G1 E{length} F{(speed|float|abs) * 60} + {% if absolute_extrude %} + M82 + {% endif %} + {% endif %} + {% endif %} + {% endif %} + [gcode_macro RESUME] description: Resume the actual running print rename_existing: RESUME_BASE @@ -681,10 +703,10 @@ variable_restore_idle_timeout: 0 variable_idle_state: False variable_filament_state: "" variable_change_runout: "" -variable_autoshift: False variable_resume_extruder: "" gcode: ##### get user parameters or use default ##### + {% set autoshift = printer.save_variables.variables.auto_change_nozzle|default(False) %} {% set client = printer['gcode_macro _CLIENT_VARIABLE']|default({}) %} {% set do_resume = False %} {% set runout = True %} @@ -704,16 +726,10 @@ gcode: {% set do_resume = True %} {% elif can_extrude %} {% set do_resume = True %} - {% else %} - RESPOND TYPE=error MSG='{"Resume aborted !!! \"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder}' - {% set _d = prompt_txt.append("\"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder) %} {% endif %} #### Printer comming out of regular PAUSE state #### {% elif can_extrude %} {% set do_resume = True %} - {% else %} - RESPOND TYPE=error MSG='{"Resume aborted !!! \"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder}' - {% set _d = prompt_txt.append("\"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder) %} {% endif %} _ACT_RESUME DO_RESUME={do_resume} @@ -735,17 +751,17 @@ gcode: _CLIENT_EXTRUDE RESUME_BASE VELOCITY={params.VELOCITY|default(sp_move)} SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=change_runout VALUE="None" - SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=autoshift VALUE="False" {% else %} - {% set _d = prompt_txt.append("\"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder) %} + {% set msg = "Left" if printer.toolhead.extruder == "extruder" else "Right" %} + {% set _d = prompt_txt.append("%s extruder not hot enough, will reheat and continue." % msg) %} {% endif %} {% else %} - RESPOND TYPE=error MSG='{"Resume aborted !!! \"%s\" detects no filament, please load filament and press RESUME" % printer.toolhead.extruder}' - {% set _d = prompt_txt.append("\"%s\" detects no filament, please load filament and press RESUME" % printer.toolhead.extruder) %} + {% set msg = "Left" if printer.toolhead.extruder == "extruder" else "Right" %} + {% set _d = prompt_txt.append("%s extruder detects no filament, please load filament and continue." % msg) %} {% endif %} ##### Generate User Information box in case of abort ##### {% if not (filament_state and do_resume) %} - RESPOND TYPE=command MSG="action:prompt_begin RESUME aborted !!!" + RESPOND TYPE=command MSG="action:prompt_begin RESUME ABORTED !" {% for element in prompt_txt %} RESPOND TYPE=command MSG='{"action:prompt_text %s" % element}' {% endfor %} @@ -796,14 +812,14 @@ gcode: {% if not filament_state %} PAUSE {% if autoshift_extruder %} - SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=autoshift VALUE=True {% if printer["gcode_macro RESUME"].filament_state[target_extruder] %} RESUME {% else %} RESPOND TYPE=error MSG='{"Noting! All extruders filament has been run out."}' {% endif %} {% else %} - RESPOND TYPE=error MSG='{"Noting! \"%s\" filament has been run out." % printer.toolhead.extruder}' + {% set msg = "Left" if printer.toolhead.extruder == "extruder" else "Right" %} + RESPOND TYPE=error MSG='{"Noting! %s extruder filament has been run out." % msg}' {% endif %} {% endif %} diff --git a/config/CreatBot_D600Pro2/base.cfg b/config/CreatBot_D600Pro2/base.cfg index 9e8462ecb..8f30de32e 100644 --- a/config/CreatBot_D600Pro2/base.cfg +++ b/config/CreatBot_D600Pro2/base.cfg @@ -378,7 +378,7 @@ gcode: {% else %} PAUSE SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=change_runout VALUE='"T0"' - RESPOND TYPE=error MSG='{"Noting! extruder filament has been run out."}' + RESPOND TYPE=error MSG='{"Noting! Left extruder filament has been run out."}' {% endif %} [gcode_macro T1] @@ -405,7 +405,7 @@ gcode: {% else %} PAUSE SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=change_runout VALUE='"T1"' - RESPOND TYPE=error MSG='{"Noting! extruder1 filament has been run out."}' + RESPOND TYPE=error MSG='{"Noting! Right extruder filament has been run out."}' {% endif %} [gcode_macro PROBE_SERVO_OPEN] @@ -458,6 +458,10 @@ gcode: G92 E0 M117 Printing start... +[gcode_macro PRINT_START] +gcode: + START_PRINT + [gcode_macro END_PRINT] gcode: M400 @@ -472,6 +476,10 @@ gcode: G0 X590 Y590 F3600 # BED_MESH_CLEAR +[gcode_macro PRINT_END] +gcode: + END_PRINT + [gcode_macro LOAD_FILAMENT] variable_load_distance: 120 variable_purge_distance: 25 @@ -501,24 +509,6 @@ gcode: G1 E-{unload_distance} F{max_velocity} # fast-unload RESTORE_GCODE_STATE NAME=unload_state -[gcode_macro SET_X_OFFSET] -gcode: - {% set svv = printer.save_variables.variables %} - {% set dual_x_offset=params.S|default(-60)|float %} - SAVE_VARIABLE VARIABLE=dual_x_offset VALUE={dual_x_offset} - -[gcode_macro SET_Y_OFFSET] -gcode: - {% set svv = printer.save_variables.variables %} - {% set dual_y_offset=params.S|default(0)|float %} - SAVE_VARIABLE VARIABLE=dual_y_offset VALUE={dual_y_offset} - -[gcode_macro SET_Z_OFFSET] -gcode: - {% set svv = printer.save_variables.variables %} - {% set dual_z_offset=params.S|default(0)|float %} - SAVE_VARIABLE VARIABLE=dual_z_offset VALUE={dual_z_offset} - [gcode_macro _ACTIVATE_DEFAULT_EXTRUDER] gcode: {% if printer.toolhead.extruder == 'extruder' %} @@ -660,13 +650,13 @@ gcode: [gcode_macro _RESUME_EXTRUDER] gcode: {% set client = printer['gcode_macro RESUME']|default({}) %} - {% set autoshift_on = params.AUTOSHIFT|default(False) %} + {% set autoshift_on = params.AUTOSHIFT|default(False)|lower %} {% set toolchange = client.change_runout|lower|default("") %} {% set extruder_filament = client.filament_state.extruder %} {% set extruder1_filament = client.filament_state.extruder1 %} {% set resume_extruder = client.resume_extruder %} - {% if autoshift_on %} + {% if autoshift_on == 'true' %} {% if extruder_filament and extruder1_filament %} {% if toolchange == "t0" %} {% set resume_extruder = "extruder" %} @@ -704,8 +694,10 @@ gcode: {'index': 1, 'name': 'last_extruder1_temp'}] %} {% set temperature = "last_extruder_temp" if printer.toolhead.extruder == "extruder" else "last_extruder1_temp" %} {% set value = printer["gcode_macro RESUME"][temperature].temp %} - RESPOND TYPE=echo MSG='{"Restoring \"%s\" temperature to %3.1f\u00B0C, this may take some time" % - (printer.toolhead.extruder, value)}' + {% if printer[printer.toolhead.extruder].temperature < value-3 %} + {% set msg = "Left" if printer.toolhead.extruder == "extruder" else "Right" %} + RESPOND TYPE=echo MSG='{"Restoring %s extruder temperature, this may take some time." % msg}' + {% endif %} {% for info in extruder_info %} {% set variable = printer["gcode_macro RESUME"][info.name] %} {% if variable.restore %} @@ -725,10 +717,40 @@ gcode: [gcode_macro _USER_CANCEL] gcode: - G91 - G1 Z30 F600 ; lift nozzle + {% if 'z' in printer.toolhead.homed_axes %} + G91 + G1 Z30 F600 ; lift nozzle + {% endif %} M84 +[gcode_macro _CLIENT_EXTRUDE] +description: Extrudes, if the extruder is hot enough +gcode: + ##### get user parameters or use default ##### + {% set client = printer['gcode_macro _CLIENT_VARIABLE']|default({}) %} + {% set use_fw_retract = (client.use_fw_retract|default(false)|lower == 'true') and (printer.firmware_retraction is defined) %} + {% set length = params.LENGTH|default(client.unretract)|default(1.0)|float %} + {% set speed = params.SPEED|default(client.speed_unretract)|default(35) %} + {% set absolute_extrude = printer.gcode_move.absolute_extrude %} + ##### end of definitions ##### + {% if printer.toolhead.extruder != '' %} + {% if printer[printer.toolhead.extruder].can_extrude %} + {% if use_fw_retract %} + {% if length < 0 %} + G10 + {% else %} + G11 + {% endif %} + {% else %} + M83 + G1 E{length} F{(speed|float|abs) * 60} + {% if absolute_extrude %} + M82 + {% endif %} + {% endif %} + {% endif %} + {% endif %} + [gcode_macro RESUME] description: Resume the actual running print rename_existing: RESUME_BASE @@ -738,10 +760,10 @@ variable_restore_idle_timeout: 0 variable_idle_state: False variable_filament_state: "" variable_change_runout: "" -variable_autoshift: False variable_resume_extruder: "" gcode: ##### get user parameters or use default ##### + {% set autoshift = printer.save_variables.variables.auto_change_nozzle|default(False) %} {% set client = printer['gcode_macro _CLIENT_VARIABLE']|default({}) %} {% set do_resume = False %} {% set prompt_txt = [] %} @@ -763,16 +785,10 @@ gcode: {% set do_resume = True %} {% elif can_extrude %} {% set do_resume = True %} - {% else %} - RESPOND TYPE=error MSG='{"Resume aborted !!! \"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder}' - {% set _d = prompt_txt.append("\"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder) %} {% endif %} #### Printer comming out of regular PAUSE state #### {% elif can_extrude %} {% set do_resume = True %} - {% else %} - RESPOND TYPE=error MSG='{"Resume aborted !!! \"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder}' - {% set _d = prompt_txt.append("\"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder) %} {% endif %} _ACT_RESUME DO_RESUME={do_resume} @@ -794,17 +810,17 @@ gcode: _CLIENT_EXTRUDE RESUME_BASE VELOCITY={params.VELOCITY|default(sp_move)} SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=change_runout VALUE="None" - SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=autoshift VALUE="False" {% else %} - {% set _d = prompt_txt.append("\"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder) %} + {% set msg = "Left" if printer.toolhead.extruder == "extruder" else "Right" %} + {% set _d = prompt_txt.append("%s extruder not hot enough, will reheat and continue." % msg) %} {% endif %} {% else %} - RESPOND TYPE=error MSG='{"Resume aborted !!! \"%s\" detects no filament, please load filament and press RESUME" % printer.toolhead.extruder}' - {% set _d = prompt_txt.append("\"%s\" detects no filament, please load filament and press RESUME" % printer.toolhead.extruder) %} + {% set msg = "Left" if printer.toolhead.extruder == "extruder" else "Right" %} + {% set _d = prompt_txt.append("%s extruder detects no filament, please load filament and continue." % msg) %} {% endif %} ##### Generate User Information box in case of abort ##### {% if not (filament_state and do_resume) %} - RESPOND TYPE=command MSG="action:prompt_begin RESUME aborted !!!" + RESPOND TYPE=command MSG="action:prompt_begin RESUME ABORTED !" {% for element in prompt_txt %} RESPOND TYPE=command MSG='{"action:prompt_text %s" % element}' {% endfor %} @@ -855,14 +871,14 @@ gcode: {% if not filament_state %} PAUSE {% if autoshift_extruder %} - SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=autoshift VALUE=True {% if printer["gcode_macro RESUME"].filament_state[target_extruder] %} RESUME {% else %} RESPOND TYPE=error MSG='{"Noting! All extruders filament has been run out."}' {% endif %} {% else %} - RESPOND TYPE=error MSG='{"Noting! \"%s\" filament has been run out." % printer.toolhead.extruder}' + {% set msg = "Left" if printer.toolhead.extruder == "extruder" else "Right" %} + RESPOND TYPE=error MSG='{"Noting! %s extruder filament has been run out." % msg}' {% endif %} {% endif %} diff --git a/config/CreatBot_D600Pro2_V0/base.cfg b/config/CreatBot_D600Pro2_V0/base.cfg index 0130ccd62..143b989ea 100644 --- a/config/CreatBot_D600Pro2_V0/base.cfg +++ b/config/CreatBot_D600Pro2_V0/base.cfg @@ -314,7 +314,7 @@ gcode: {% else %} PAUSE SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=change_runout VALUE='"T0"' - RESPOND TYPE=error MSG='{"Noting! extruder filament has been run out."}' + RESPOND TYPE=error MSG='{"Noting! Left extruder filament has been run out."}' {% endif %} [gcode_macro T1] @@ -341,7 +341,7 @@ gcode: {% else %} PAUSE SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=change_runout VALUE='"T1"' - RESPOND TYPE=error MSG='{"Noting! extruder1 filament has been run out."}' + RESPOND TYPE=error MSG='{"Noting! Right extruder filament has been run out."}' {% endif %} [gcode_macro PROBE_SERVO_OPEN] @@ -394,6 +394,10 @@ gcode: G92 E0 M117 Printing start... +[gcode_macro PRINT_START] +gcode: + START_PRINT + [gcode_macro END_PRINT] gcode: M400 @@ -408,6 +412,10 @@ gcode: G0 X590 Y590 F3600 # BED_MESH_CLEAR +[gcode_macro PRINT_END] +gcode: + END_PRINT + [gcode_macro LOAD_FILAMENT] variable_load_distance: 120 variable_purge_distance: 25 @@ -437,24 +445,6 @@ gcode: G1 E-{unload_distance} F{max_velocity} # fast-unload RESTORE_GCODE_STATE NAME=unload_state -[gcode_macro SET_X_OFFSET] -gcode: - {% set svv = printer.save_variables.variables %} - {% set dual_x_offset=params.S|default(-60)|float %} - SAVE_VARIABLE VARIABLE=dual_x_offset VALUE={dual_x_offset} - -[gcode_macro SET_Y_OFFSET] -gcode: - {% set svv = printer.save_variables.variables %} - {% set dual_y_offset=params.S|default(0)|float %} - SAVE_VARIABLE VARIABLE=dual_y_offset VALUE={dual_y_offset} - -[gcode_macro SET_Z_OFFSET] -gcode: - {% set svv = printer.save_variables.variables %} - {% set dual_z_offset=params.S|default(0)|float %} - SAVE_VARIABLE VARIABLE=dual_z_offset VALUE={dual_z_offset} - [gcode_macro _ACTIVATE_DEFAULT_EXTRUDER] gcode: {% if printer.toolhead.extruder == 'extruder' %} @@ -596,13 +586,13 @@ gcode: [gcode_macro _RESUME_EXTRUDER] gcode: {% set client = printer['gcode_macro RESUME']|default({}) %} - {% set autoshift_on = params.AUTOSHIFT|default(False) %} + {% set autoshift_on = params.AUTOSHIFT|default(False)|lower %} {% set toolchange = client.change_runout|lower|default("") %} {% set extruder_filament = client.filament_state.extruder %} {% set extruder1_filament = client.filament_state.extruder1 %} {% set resume_extruder = client.resume_extruder|default("extruder") %} - {% if autoshift_on %} + {% if autoshift_on == 'true' %} {% if extruder_filament and extruder1_filament %} {% if toolchange == "t0" %} {% set resume_extruder = "extruder" %} @@ -640,8 +630,10 @@ gcode: {'index': 1, 'name': 'last_extruder1_temp'}] %} {% set temperature = "last_extruder_temp" if printer.toolhead.extruder == "extruder" else "last_extruder1_temp" %} {% set value = printer["gcode_macro RESUME"][temperature].temp %} - RESPOND TYPE=echo MSG='{"Restoring \"%s\" temperature to %3.1f\u00B0C, this may take some time" % - (printer.toolhead.extruder, value)}' + {% if printer[printer.toolhead.extruder].temperature < value-3 %} + {% set msg = "Left" if printer.toolhead.extruder == "extruder" else "Right" %} + RESPOND TYPE=echo MSG='{"Restoring %s extruder temperature, this may take some time." % msg}' + {% endif %} {% for info in extruder_info %} {% set variable = printer["gcode_macro RESUME"][info.name] %} {% if variable.restore %} @@ -661,10 +653,40 @@ gcode: [gcode_macro _USER_CANCEL] gcode: - G91 - G1 Z30 F600 ; lift nozzle + {% if 'z' in printer.toolhead.homed_axes %} + G91 + G1 Z30 F600 ; lift nozzle + {% endif %} M84 +[gcode_macro _CLIENT_EXTRUDE] +description: Extrudes, if the extruder is hot enough +gcode: + ##### get user parameters or use default ##### + {% set client = printer['gcode_macro _CLIENT_VARIABLE']|default({}) %} + {% set use_fw_retract = (client.use_fw_retract|default(false)|lower == 'true') and (printer.firmware_retraction is defined) %} + {% set length = params.LENGTH|default(client.unretract)|default(1.0)|float %} + {% set speed = params.SPEED|default(client.speed_unretract)|default(35) %} + {% set absolute_extrude = printer.gcode_move.absolute_extrude %} + ##### end of definitions ##### + {% if printer.toolhead.extruder != '' %} + {% if printer[printer.toolhead.extruder].can_extrude %} + {% if use_fw_retract %} + {% if length < 0 %} + G10 + {% else %} + G11 + {% endif %} + {% else %} + M83 + G1 E{length} F{(speed|float|abs) * 60} + {% if absolute_extrude %} + M82 + {% endif %} + {% endif %} + {% endif %} + {% endif %} + [gcode_macro RESUME] description: Resume the actual running print rename_existing: RESUME_BASE @@ -674,10 +696,10 @@ variable_restore_idle_timeout: 0 variable_idle_state: False variable_filament_state: "" variable_change_runout: "" -variable_autoshift: False variable_resume_extruder: "" gcode: ##### get user parameters or use default ##### + {% set autoshift = printer.save_variables.variables.auto_change_nozzle|default(False) %} {% set client = printer['gcode_macro _CLIENT_VARIABLE']|default({}) %} {% set do_resume = False %} {% set prompt_txt = [] %} @@ -699,16 +721,10 @@ gcode: {% set do_resume = True %} {% elif can_extrude %} {% set do_resume = True %} - {% else %} - RESPOND TYPE=error MSG='{"Resume aborted !!! \"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder}' - {% set _d = prompt_txt.append("\"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder) %} {% endif %} #### Printer comming out of regular PAUSE state #### {% elif can_extrude %} {% set do_resume = True %} - {% else %} - RESPOND TYPE=error MSG='{"Resume aborted !!! \"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder}' - {% set _d = prompt_txt.append("\"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder) %} {% endif %} _ACT_RESUME DO_RESUME={do_resume} @@ -730,17 +746,17 @@ gcode: _CLIENT_EXTRUDE RESUME_BASE VELOCITY={params.VELOCITY|default(sp_move)} SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=change_runout VALUE="None" - SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=autoshift VALUE="False" {% else %} - {% set _d = prompt_txt.append("\"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder) %} + {% set msg = "Left" if printer.toolhead.extruder == "extruder" else "Right" %} + {% set _d = prompt_txt.append("%s extruder not hot enough, will reheat and continue." % msg) %} {% endif %} {% else %} - RESPOND TYPE=error MSG='{"Resume aborted !!! \"%s\" detects no filament, please load filament and press RESUME" % printer.toolhead.extruder}' - {% set _d = prompt_txt.append("\"%s\" detects no filament, please load filament and press RESUME" % printer.toolhead.extruder) %} + {% set msg = "Left" if printer.toolhead.extruder == "extruder" else "Right" %} + {% set _d = prompt_txt.append("%s extruder detects no filament, please load filament and continue." % msg) %} {% endif %} ##### Generate User Information box in case of abort ##### {% if not (filament_state and do_resume) %} - RESPOND TYPE=command MSG="action:prompt_begin RESUME aborted !!!" + RESPOND TYPE=command MSG="action:prompt_begin RESUME ABORTED !" {% for element in prompt_txt %} RESPOND TYPE=command MSG='{"action:prompt_text %s" % element}' {% endfor %} @@ -791,14 +807,14 @@ gcode: {% if not filament_state %} PAUSE {% if autoshift_extruder %} - SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=autoshift VALUE=True {% if printer["gcode_macro RESUME"].filament_state[target_extruder] %} RESUME {% else %} RESPOND TYPE=error MSG='{"Noting! All extruders filament has been run out."}' {% endif %} {% else %} - RESPOND TYPE=error MSG='{"Noting! \"%s\" filament has been run out." % printer.toolhead.extruder}' + {% set msg = "Left" if printer.toolhead.extruder == "extruder" else "Right" %} + RESPOND TYPE=error MSG='{"Noting! %s extruder filament has been run out." % msg}' {% endif %} {% endif %} diff --git a/config/CreatBot_F430NX/base.cfg b/config/CreatBot_F430NX/base.cfg index 87df64a4e..ce95ad25f 100644 --- a/config/CreatBot_F430NX/base.cfg +++ b/config/CreatBot_F430NX/base.cfg @@ -102,10 +102,10 @@ cs_pin: PE8 spi_software_sclk_pin: PB3 spi_software_mosi_pin: PB5 spi_software_miso_pin: PB4 -run_current: 1.0 +run_current: 1.5 interpolate: True sense_resistor: 0.075 -stealthchop_threshold: 200 +stealthchop_threshold: 300 [stepper_y] step_pin: PD4 @@ -180,7 +180,7 @@ max_temp: 80 [verify_heater chamber] max_error: 120 -hysteresis: 0 +hysteresis: 100 check_gain_time: 3600 heating_gain: 0.01 @@ -200,6 +200,10 @@ max_power: 1.0 shutdown_speed: 0.0 kick_start_time: 1.0 +[controller_fan _controller_fan] +pin: PC6 +fan_speed: 1 + [delayed_gcode INIT_LIGHT] initial_duration:0.01 gcode: @@ -215,7 +219,7 @@ initial_WHITE: 0 [neopixel _Status_light] pin: PB8 chain_count: 1 -color_order: RGB +color_order: GRB initial_RED: 0.3 initial_GREEN: 0.3 initial_BLUE: 0.3 @@ -438,12 +442,9 @@ gcode: {% set x_home = true %} {% endif %} {% if printer.toolhead.extruder != 'extruder' or x_home %} - SAVE_GCODE_STATE NAME=park0 - G90 _PARK_{printer.toolhead.extruder} ACTIVATE_EXTRUDER EXTRUDER=extruder SET_DUAL_CARRIAGE CARRIAGE=0 - RESTORE_GCODE_STATE NAME=park0 {% if "z" in printer.toolhead.homed_axes | lower %} SET_GCODE_OFFSET Z=0 MOVE=1 {% else %} @@ -451,12 +452,15 @@ gcode: {% endif %} SET_GCODE_OFFSET Y=0 SET_GCODE_OFFSET X=0 + SAVE_GCODE_STATE NAME=park0 + G90 G1 X0 F6000 + RESTORE_GCODE_STATE NAME=park0 {% endif %} {% else %} PAUSE SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=change_runout VALUE='"T0"' - RESPOND TYPE=error MSG='{"Noting! extruder filament has been run out."}' + RESPOND TYPE=error MSG='{"Noting! Left extruder filament has been run out."}' {% endif %} [gcode_macro _PARK_extruder1] @@ -481,11 +485,12 @@ gcode: {% endif %} {% if printer.toolhead.extruder != 'extruder1' or x_home %} - SAVE_GCODE_STATE NAME=park1 - G90 _PARK_{printer.toolhead.extruder} ACTIVATE_EXTRUDER EXTRUDER=extruder1 SET_DUAL_CARRIAGE CARRIAGE=1 + SAVE_GCODE_STATE NAME=park1 + G90 + G1 X455 F6000 RESTORE_GCODE_STATE NAME=park1 {% if "z" in printer.toolhead.homed_axes | lower %} SET_GCODE_OFFSET Z={z_offset} MOVE=1 @@ -494,43 +499,53 @@ gcode: {% endif %} SET_GCODE_OFFSET Y={y_offset} SET_GCODE_OFFSET X={x_offset} - G1 X455 F6000 {% endif %} {% else %} PAUSE SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=change_runout VALUE='"T1"' - RESPOND TYPE=error MSG='{"Noting! extruder1 filament has been run out."}' + RESPOND TYPE=error MSG='{"Noting! Right extruder filament has been run out."}' {% endif %} [gcode_macro ACTIVATE_COPY_MODE] gcode: - SET_GCODE_VARIABLE MACRO=_SET_DUAL_MODE VARIABLE=dual_mode VALUE='"copy"' + _SET_DUAL_MODE MODE="copy" [gcode_macro ACTIVATE_MIRROR_MODE] gcode: - SET_GCODE_VARIABLE MACRO=_SET_DUAL_MODE VARIABLE=dual_mode VALUE='"mirror"' + _SET_DUAL_MODE MODE="mirror" [gcode_macro _ACTIVATE_PRIMARY_MODE] gcode: - SET_GCODE_VARIABLE MACRO=_SET_DUAL_MODE VARIABLE=dual_mode VALUE='"primary"' + _SET_DUAL_MODE MODE="primary" [gcode_macro _SET_DUAL_MODE] variable_dual_mode: "primary" gcode: - G90 - SET_DUAL_CARRIAGE CARRIAGE=0 MODE=PRIMARY - G1 X0 F6000 - ACTIVATE_EXTRUDER EXTRUDER=extruder - SET_DUAL_CARRIAGE CARRIAGE=1 MODE=PRIMARY - {% if dual_mode == "copy" %} - G1 X227.5 F6000 - SET_DUAL_CARRIAGE CARRIAGE=1 MODE=COPY - {% elif dual_mode == "mirror" %} - G1 X455 F6000 - SET_DUAL_CARRIAGE CARRIAGE=1 MODE=MIRROR + {% set mode = params.MODE|default("primary") %} + {% if 'xyz' in printer.toolhead.homed_axes %} + {% if mode == "copy" or mode == "mirror"%} + G90 + SET_DUAL_CARRIAGE CARRIAGE=0 MODE=PRIMARY + G1 X0 F6000 + ACTIVATE_EXTRUDER EXTRUDER=extruder + SET_DUAL_CARRIAGE CARRIAGE=1 MODE=PRIMARY + {% endif %} + {% if mode == "copy" %} + G1 X227.5 F6000 + SET_DUAL_CARRIAGE CARRIAGE=1 MODE=COPY + SYNC_EXTRUDER_MOTION EXTRUDER=extruder1 MOTION_QUEUE=extruder + {% elif mode == "mirror" %} + G1 X455 F6000 + SET_DUAL_CARRIAGE CARRIAGE=1 MODE=MIRROR + SYNC_EXTRUDER_MOTION EXTRUDER=extruder1 MOTION_QUEUE=extruder + {% elif mode == "primary" %} + SYNC_EXTRUDER_MOTION EXTRUDER=extruder1 MOTION_QUEUE=extruder1 + ACTIVATE_EXTRUDER EXTRUDER=extruder + SET_DUAL_CARRIAGE CARRIAGE=0 + {% endif %} + _RUNOUT_HANDLE {% endif %} - SYNC_EXTRUDER_MOTION EXTRUDER=extruder1 MOTION_QUEUE=extruder - _RUNOUT_HANDLE + SET_GCODE_VARIABLE MACRO=_SET_DUAL_MODE VARIABLE=dual_mode VALUE='"{mode}"' [gcode_macro PROBE_SERVO_OPEN] gcode: @@ -588,6 +603,10 @@ gcode: G92 E0 M117 Printing start... +[gcode_macro PRINT_START] +gcode: + START_PRINT + [gcode_macro END_PRINT] gcode: M400 @@ -595,10 +614,14 @@ gcode: G1 E-10.0 F3600 G91 {% if printer["dual_carriage"] is defined %} - G0 Z1.00 F6000 - _PARK_extruder - _PARK_extruder1 - _ACTIVATE_PRIMARY_MODE + {% set dual_mode = printer['gcode_macro _SET_DUAL_MODE'].dual_mode|default("primary") %} + {% if dual_mode == "copy" or dual_mode == "mirror" %} + G0 Z1.00 F6000 + G90 + _PARK_extruder + _PARK_extruder1 + G91 + {% endif %} {% else %} G0 Z1.00 X20.0 Y20.0 F6000 {% endif %} @@ -609,6 +632,10 @@ gcode: G0 Y300 F3600 # BED_MESH_CLEAR +[gcode_macro PRINT_END] +gcode: + END_PRINT + [gcode_macro SET_LED] rename_existing: LED_SET gcode: @@ -633,23 +660,14 @@ gcode: LED_SET LED={led_name} RED={red} GREEN={green} BLUE={blue} WHITE={white} INDEX={index} TRANSMIT={transmit} SYNC={sync} {% endif %} -[gcode_macro SET_X_OFFSET] -gcode: - {% set svv = printer.save_variables.variables %} - {% set dual_x_offset=params.S|default(0)|float %} - SAVE_VARIABLE VARIABLE=dual_x_offset VALUE={dual_x_offset} - -[gcode_macro SET_Y_OFFSET] -gcode: - {% set svv = printer.save_variables.variables %} - {% set dual_y_offset=params.S|default(0)|float %} - SAVE_VARIABLE VARIABLE=dual_y_offset VALUE={dual_y_offset} - -[gcode_macro SET_Z_OFFSET] -gcode: - {% set svv = printer.save_variables.variables %} - {% set dual_z_offset=params.S|default(0)|float %} - SAVE_VARIABLE VARIABLE=dual_z_offset VALUE={dual_z_offset} +[led_effect runstate] +leds: + neopixel:_Status_light +autostart: true +frame_rate: 24 +hot: extruder extruder1 heater_bed chamber +layers: + status 0 0 top (0.3, 0.3, 0.3),( 0, 0, 0.3),(0, 0.3, 0) [gcode_macro LOAD_FILAMENT] variable_load_distance: 90 @@ -681,15 +699,18 @@ gcode: rename_existing: C28 gcode: {% set homing_cmd = ''%} - {% set dual_mode = printer['gcode_macro _SET_DUAL_MODE'].dual_mode|default("primary") %} + {% set save_dual_mode = printer['gcode_macro _SET_DUAL_MODE'].dual_mode|default("primary") %} {% set do_x = 'X' in params|string %} {% set do_y = 'Y' in params|string %} {% set do_z = 'Z' in params|string %} - + {% if save_dual_mode == "copy" or save_dual_mode == "mirror" %} + _SET_DUAL_MODE MODE="primary" + {% endif %} {% if do_x %} {% set homing_cmd = 'X ' %} {% endif %} {% if do_y %} + SET_STEPPER_ENABLE STEPPER=stepper_y ENABLE=1 {% set homing_cmd = homing_cmd + 'Y ' %} {% endif %} {% if do_z %} @@ -700,6 +721,7 @@ gcode: {% endif %} {% endif %} {% if not homing_cmd %} + SET_STEPPER_ENABLE STEPPER=stepper_y ENABLE=1 C28 _RESTORE_DEFAULT_EXTRUDER {% else %} @@ -708,8 +730,8 @@ gcode: _RESTORE_DEFAULT_EXTRUDER {% endif %} {% endif %} - {% if dual_mode == "copy" or dual_mode == "mirror" %} - _SET_DUAL_MODE + {% if save_dual_mode == "copy" or save_dual_mode == "mirror" %} + _SET_DUAL_MODE MODE={save_dual_mode} {% endif %} [gcode_macro M109] @@ -824,8 +846,10 @@ gcode: {'index': 1, 'name': 'last_extruder1_temp'}] %} {% set temperature = "last_extruder_temp" if printer.toolhead.extruder == "extruder" else "last_extruder1_temp" %} {% set value = printer["gcode_macro RESUME"][temperature].temp %} - RESPOND TYPE=echo MSG='{"Restoring \"%s\" temperature to %3.1f\u00B0C, this may take some time" % - (printer.toolhead.extruder, value)}' + {% if printer[printer.toolhead.extruder].temperature < value-3 %} + {% set msg = "Left" if printer.toolhead.extruder == "extruder" else "Right" %} + RESPOND TYPE=echo MSG='{"Restoring %s extruder temperature, this may take some time." % msg}' + {% endif %} {% for info in extruder_info %} {% set variable = printer["gcode_macro RESUME"][info.name] %} {% if variable.restore %} @@ -846,13 +870,13 @@ gcode: [gcode_macro _RESUME_EXTRUDER] gcode: {% set client = printer['gcode_macro RESUME']|default({}) %} - {% set autoshift_on = params.AUTOSHIFT|default(False) %} + {% set autoshift_on = params.AUTOSHIFT|default(False)|lower %} {% set toolchange = client.change_runout|lower|default("") %} {% set extruder_filament = client.filament_state.extruder %} {% set extruder1_filament = client.filament_state.extruder1 %} {% set resume_extruder = client.resume_extruder|default("extruder") %} - {% if autoshift_on %} + {% if autoshift_on == 'true' %} {% if extruder_filament and extruder1_filament %} {% if toolchange == "t0" %} {% set resume_extruder = "extruder" %} @@ -885,10 +909,40 @@ gcode: [gcode_macro _USER_CANCEL] gcode: - G91 - G1 Z30 F600 ; lift nozzle + {% if 'z' in printer.toolhead.homed_axes %} + G91 + G1 Z30 F600 ; lift nozzle + {% endif %} M84 +[gcode_macro _CLIENT_EXTRUDE] +description: Extrudes, if the extruder is hot enough +gcode: + ##### get user parameters or use default ##### + {% set client = printer['gcode_macro _CLIENT_VARIABLE']|default({}) %} + {% set use_fw_retract = (client.use_fw_retract|default(false)|lower == 'true') and (printer.firmware_retraction is defined) %} + {% set length = params.LENGTH|default(client.unretract)|default(1.0)|float %} + {% set speed = params.SPEED|default(client.speed_unretract)|default(35) %} + {% set absolute_extrude = printer.gcode_move.absolute_extrude %} + ##### end of definitions ##### + {% if printer.toolhead.extruder != '' %} + {% if printer[printer.toolhead.extruder].can_extrude %} + {% if use_fw_retract %} + {% if length < 0 %} + G10 + {% else %} + G11 + {% endif %} + {% else %} + M83 + G1 E{length} F{(speed|float|abs) * 60} + {% if absolute_extrude %} + M82 + {% endif %} + {% endif %} + {% endif %} + {% endif %} + [gcode_macro RESUME] description: Resume the actual running print rename_existing: RESUME_BASE @@ -899,10 +953,10 @@ variable_idle_state: False variable_resume_dual: False variable_filament_state: "" variable_change_runout: "" -variable_autoshift: False variable_resume_extruder: "" gcode: ##### get user parameters or use default ##### + {% set autoshift = printer.save_variables.variables.auto_change_nozzle|default(False) %} {% set client = printer['gcode_macro _CLIENT_VARIABLE']|default({}) %} {% set do_resume = False %} {% set prompt_txt = [] %} @@ -930,16 +984,10 @@ gcode: {% set do_resume = True %} {% elif can_extrude %} {% set do_resume = True %} - {% else %} - RESPOND TYPE=error MSG='{"Resume aborted !!! \"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder}' - {% set _d = prompt_txt.append("\"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder) %} {% endif %} #### Printer comming out of regular PAUSE state #### {% elif can_extrude %} {% set do_resume = True %} - {% else %} - RESPOND TYPE=error MSG='{"Resume aborted !!! \"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder}' - {% set _d = prompt_txt.append("\"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder) %} {% endif %} _ACT_RESUME DO_RESUME={do_resume} @@ -961,17 +1009,17 @@ gcode: _CLIENT_EXTRUDE RESUME_BASE VELOCITY={params.VELOCITY|default(sp_move)} SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=change_runout VALUE="None" - SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=autoshift VALUE="False" {% else %} - {% set _d = prompt_txt.append("\"%s\" not hot enough, please heat up again and press RESUME" % printer.toolhead.extruder) %} + {% set msg = "Left" if printer.toolhead.extruder == "extruder" else "Right" %} + {% set _d = prompt_txt.append("%s extruder not hot enough, will reheat and continue." % msg) %} {% endif %} {% else %} - RESPOND TYPE=error MSG='{"Resume aborted !!! \"%s\" detects no filament, please load filament and press RESUME" % printer.toolhead.extruder}' - {% set _d = prompt_txt.append("\"%s\" detects no filament, please load filament and press RESUME" % printer.toolhead.extruder) %} + {% set msg = "Left" if printer.toolhead.extruder == "extruder" else "Right" %} + {% set _d = prompt_txt.append("%s extruder detects no filament, please load filament and continue." % msg) %} {% endif %} ##### Generate User Information box in case of abort ##### {% if not (filament_state and do_resume) %} - RESPOND TYPE=command MSG="action:prompt_begin RESUME aborted !!!" + RESPOND TYPE=command MSG="action:prompt_begin RESUME ABORTED !" {% for element in prompt_txt %} RESPOND TYPE=command MSG='{"action:prompt_text %s" % element}' {% endfor %} @@ -1029,14 +1077,14 @@ gcode: {% if not filament_state %} PAUSE {% if autoshift_extruder and idex == False %} - SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=autoshift VALUE=True {% if printer["gcode_macro RESUME"].filament_state[target_extruder] %} RESUME {% else %} RESPOND TYPE=error MSG='{"Noting! All extruders filament has been run out."}' {% endif %} {% else %} - RESPOND TYPE=error MSG='{"Noting! \"%s\" filament has been run out." % printer.toolhead.extruder}' + {% set msg = "Left" if printer.toolhead.extruder == "extruder" else "Right" %} + RESPOND TYPE=error MSG='{"Noting! %s extruder filament has been run out." % msg}' {% endif %} {% endif %} @@ -1126,8 +1174,8 @@ gcode: {% set svv = printer.save_variables.variables %} {% set adaptive_mesh = svv.adaptive_meshing|default(false)|lower %} {% if printer["dual_carriage"] is defined %} - {% set current_idex_mode = printer["dual_carriage"].carriage_1|lower %} - {% if current_idex_mode == "copy" or idex_mode == "mirror" %} + {% set current_idex_mode = printer['gcode_macro _SET_DUAL_MODE'].dual_mode|default("primary") %} + {% if current_idex_mode == "copy" or current_idex_mode == "mirror" %} {% set idex_mode = True %} {% endif %} {% endif %} diff --git a/klippy/extras/led_effect.py b/klippy/extras/led_effect.py new file mode 100644 index 000000000..b79826159 --- /dev/null +++ b/klippy/extras/led_effect.py @@ -0,0 +1,1556 @@ +# Support for addressable LED visual effects +# using neopixel and dotstar LEDs +# +# Copyright (C) 2020 Paul McGowan <mental405@gmail.com> +# co-authored by Julian Schill <j.schill@web.de> +# +# This file may be distributed under the terms of the GNU GPLv3 license. +from math import cos, exp, pi +from random import randint + +ANALOG_SAMPLE_TIME = 0.001 +ANALOG_SAMPLE_COUNT = 5 +ANALOG_REPORT_TIME = 0.05 + +COLORS = 4 + +###################################################################### +# Custom color value list, returns lists of [r, g ,b] values +# from a one dimensional list +###################################################################### + +class colorArray(list): + def __init__(self, num_colors, kwargs): + self.n=num_colors + super(colorArray,self).__init__(kwargs) + + def __getitem__(self, a): + if isinstance(a, int): + return super(colorArray, self).__getitem__( + slice(a*self.n, a*self.n+self.n)) + if isinstance(a, slice): + start = a.start*self.n if a.start != None else None + stop = a.stop*self.n if a.stop != None else None + return colorArray(self.n, + super(colorArray, self).__getitem__( + slice(start, stop, a.step))) + def __getslice__(self, a, b): + return self.__getitem__(slice(a,b)) + def __setitem__(self, a, v): + if isinstance(a, int): + for i in range(self.n): + super(colorArray, self).__setitem__(a*self.n + i, v[i]) + def __len__(self): + return super(colorArray, self).__len__() // self.n + def reverse(self): + self.__init__(self.n, [c for cl in range(len(self)-1,-1, -1) + for c in self[cl]]) + def shift(self, shift=1, direction=True): + if direction: + shift *= -1 + self.__init__(self.n, self[shift:] + self[:shift]) + def padLeft(self, v, a): + self.__init__(self.n, v * a + self) + def padRight(self, v, a): + self += v * a + +###################################################################### +# LED Effect handler +###################################################################### + +class ledFrameHandler: + def __init__(self, config): + self.printer = config.get_printer() + self.gcode = self.printer.lookup_object('gcode') + self.printer.load_object(config, "display_status") + self.printer.load_object(config, "print_stats") + self.heaters = {} + self.hots = {} + self.printProgress = 0 + self.effects = [] + self.stepperPositions = [0.0,0.0,0.0] + self.stepperTimer = None + self.heaterCurrent = {} + self.heaterTarget = {} + self.heaterLast = {} + self.heaterTimer = None + self.progressTimer = None + self.hotTarget = {} + self.homing = {} + self.homing_start_flag = {} + self.homing_end_flag = {} + self.runStatus = {} + self.runtStatusMsg = {} + self.printer.register_event_handler('klippy:ready', self._handle_ready) + self.printer.register_event_handler("homing:homing_move_begin", + self._handle_homing_move_begin) + self.printer.register_event_handler("homing:homing_move_end", + self._handle_homing_move_end) + self.ledChains=[] + self.gcode.register_command('STOP_LED_EFFECTS', + self.cmd_STOP_LED_EFFECTS, + desc=self.cmd_STOP_LED_EFFECTS_help) + self.shutdown = False + + cmd_STOP_LED_EFFECTS_help = 'Stops all led_effects' + + def _handle_ready(self): + self.shutdown = False + self.reactor = self.printer.get_reactor() + self.printer.register_event_handler('klippy:shutdown', + self._handle_shutdown) + self.printProgress = 0 + self.runStatus = {} + self.runtStatusMsg = {} + self.displayStatus = self.printer.lookup_object('display_status') + self.printStatus = self.printer.lookup_object('print_stats') + if not self.progressTimer: + self.progressTimer = self.reactor.register_timer(self._pollProgress, + self.reactor.NOW) + self.StatusTimer = self.reactor.register_timer(self._pollStatus, + self.reactor.NOW) + self.frameTimer = self.reactor.register_timer(self._getFrames, + self.reactor.NOW) + + def _handle_shutdown(self): + self.shutdown = True + for effect in self.effects: + if not effect.runOnShutown: + for chain in self.ledChains: + chain.led_helper.set_color(None, (0.0, 0.0, 0.0, 0.0)) + chain.led_helper.update_func(chain.led_helper.led_state, None) + + pass + + def _handle_homing_move_begin(self, hmove): + endstops_being_homed = [name for es,name in hmove.endstops] + + for endstop in endstops_being_homed: + if endstop in self.homing_start_flag: + self.homing_start_flag[endstop] += 1 + else: + self.homing_start_flag[endstop] = 0 + + self.homing[endstop]=True + + def _handle_homing_move_end(self, hmove): + endstops_being_homed = [name for es,name in hmove.endstops] + + for endstop in endstops_being_homed: + if endstop in self.homing_end_flag: + self.homing_end_flag[endstop] += 1 + else: + self.homing_end_flag[endstop] = 0 + self.homing[endstop]=False + + def addEffect(self, effect): + + if effect.heater: + effect.heater=effect.heater.strip('\"\'') + if effect.heater.startswith("temperature_fan ") or effect.heater.startswith("temperature_sensor "): + self.heaters[effect.heater] = self.printer.lookup_object(effect.heater) + else: + pheater = self.printer.lookup_object('heaters') + self.heaters[effect.heater] = pheater.lookup_heater(effect.heater) + self.heaterLast[effect.heater] = 100 + self.heaterCurrent[effect.heater] = 0 + self.heaterTarget[effect.heater] = 0 + + if not self.heaterTimer: + self.heaterTimer = self.reactor.register_timer(self._pollHeater, + self.reactor.NOW) + if effect.hot: + effect.hot=effect.hot.strip('\"\'').split(' ') + pheater = self.printer.lookup_object('heaters') + for i in range(len(effect.hot)): + self.hots[effect.hot[i]] = pheater.lookup_heater(effect.hot[i]) + self.heaterTarget[effect.hot[i]] = 0 + + if not self.progressTimer: + self.progressTimer = self.reactor.register_timer(self._pollStatus, + self.reactor.NOW) + + if effect.stepper: + self.toolhead = self.printer.lookup_object('toolhead') + self.kin = self.toolhead.get_kinematics() + + if not self.stepperTimer: + self.stepperTimer = self.reactor.register_timer( + self._pollStepper, + self.reactor.NOW) + + self.effects.append(effect) + + def _pollHeater(self, eventtime): + for heater in self.heaters.keys(): + current, target = self.heaters[heater].get_temp(eventtime) + self.heaterCurrent[heater] = current + self.heaterTarget[heater] = target + if target > 0: + self.heaterLast[heater] = target + return eventtime + 0.3 #sensors get updated every 300ms + + def _pollStepper(self, eventtime): + + kin_spos = {s.get_name(): s.get_commanded_position() + for s in self.kin.get_steppers()} + + pos = self.kin.calc_position(kin_spos) + + for i in range(3): + if pos[i] >= self.kin.axes_min[i] and pos[i] <= self.kin.axes_max[i]: + self.stepperPositions[i] = int( + ((pos[i] - self.kin.axes_min[i]) / \ + (self.kin.axes_max[i] - self.kin.axes_min[i]) + * 100)- 1) + return eventtime + 0.5 + + def _pollProgress(self, eventtime): + status = self.displayStatus.get_status(eventtime) + p = status.get('progress') + if p is not None: + self.printProgress = int(p * 100) + return eventtime + 1 + + def _pollStatus(self, eventtime): + for heater in self.hots.keys(): + current, target = self.hots[heater].get_temp(eventtime) + self.hotTarget[heater] = target + + sta = self.printStatus.get_status(eventtime) + p = sta.get('state') + msg = sta.get('message') + if p is not None: + self.runStatus = p + if msg is not None: + self.runtStatusMsg = msg + return eventtime + 0.5 + + def _getColorData(self, colors, fade): + clamp = (lambda x : 0.0 if x < 0.0 else 1.0 if x > 1.0 else x) + colors = [x*clamp(fade) for x in colors] + colors=colors + [0.0] * (4 - len(colors)) + colors=colors[:4] + colors = [clamp(x) for x in colors] + return tuple(colors) + + def _getFrames(self, eventtime): + chainsToUpdate = set() + + frames = [(effect, effect.getFrame(eventtime)) for effect in self.effects] + + #first set all LEDs to 0, that should be updated + for effect, (frame, update) in frames: + if update: + for i in range(effect.ledCount): + chain,index=effect.leds[i] + chain.led_helper.led_state[index] = (0.0, 0.0, 0.0, 0.0) + chainsToUpdate.add(chain) + + #then sum up all effects for that LEDs + for effect, (frame, update) in frames: + if update: + for i in range(effect.ledCount): + chain,index=effect.leds[i] + + current_state=list(chain.led_helper.led_state[index]) + effect_state=self._getColorData(frame[i*COLORS:i*COLORS+COLORS], + effect.fadeValue) + + next_state=[min(1.0,a+b) for a,b in \ + zip(current_state, effect_state)] + + chain.led_helper.led_state[index] = tuple(next_state) + chainsToUpdate.add(chain) + + for chain in chainsToUpdate: + if hasattr(chain,"prev_data"): + chain.prev_data = None # workaround to force update of dotstars + if not self.shutdown: + chain.led_helper.update_func(chain.led_helper.led_state, None) + if self.effects: + next_eventtime=min(self.effects, key=lambda x: x.nextEventTime)\ + .nextEventTime + else: + next_eventtime = eventtime + # run at least with 10Hz + next_eventtime=min(next_eventtime, eventtime + 0.1) + return next_eventtime + + def parse_chain(self, chain): + chain = chain.strip() + leds=[] + parms = [parameter.strip() for parameter in chain.split() + if parameter.strip()] + if parms: + chainName=parms[0].replace(':',' ') + ledIndices = ''.join(parms[1:]).strip('()').split(',') + for led in ledIndices: + if led: + if '-' in led: + start, stop = map(int,led.split('-')) + if stop == start: + ledList = [start-1] + elif stop > start: + ledList = list(range(start-1, stop)) + else: + ledList = list(reversed(range(stop-1, start))) + for i in ledList: + leds.append(int(i)) + else: + for i in led.split(','): + leds.append(int(i)-1) + + return chainName, leds + else: + return None, None + + def cmd_STOP_LED_EFFECTS(self, gcmd): + ledParam = gcmd.get('LEDS', "") + stopAll = (ledParam == "") + + for effect in self.effects: + stopEffect = stopAll + if not stopAll: + try: + chainName, ledIndices = self.parse_chain(ledParam) + chain = self.printer.lookup_object(chainName) + except Exception as e: + raise gcmd.error("Unknown LED '%s'" % (ledParam,)) + + if ledIndices == [] and chain in effect.ledChains: + stopEffect = True + else: + for index in ledIndices: + if (chain,index) in effect.leds: + stopEffect=True + + if stopEffect: + if effect.enabled: + effect.set_fade_time(gcmd.get_float('FADETIME', 0.0)) + effect.set_enabled(False) + +def load_config(config): + return ledFrameHandler(config) + +###################################################################### +# LED Effect +###################################################################### + +class ledEffect: + def __init__(self, config): + self.config = config + self.printer = config.get_printer() + self.gcode = self.printer.lookup_object('gcode') + self.gcode_macro = self.printer.load_object(config, 'gcode_macro') + self.handler = self.printer.load_object(config, 'led_effect') + self.frameRate = 1.0 / config.getfloat('frame_rate', + default=24, minval=1, maxval=60) + self.enabled = False + self.iteration = 0 + self.layers = [] + self.analogValue = 0 + self.button_state = 0 + self.fadeValue = 0.0 + self.fadeTime = 0.0 + self.fadeEndTime = 0 + + #Basic functions for layering colors. t=top and b=bottom color + self.blendingModes = { + 'top' : (lambda t, b: t ), + 'bottom' : (lambda t, b: b ), + 'add' : (lambda t, b: t + b ), + 'subtract' : (lambda t, b: (b - t) * (b - t > 0)), + 'subtract_b': (lambda t, b: (t - b) * (t - b > 0)), + 'difference': (lambda t, b: (t - b) * (t > b) + (b - t) * (t <= b)), + 'average' : (lambda t, b: 0.5 * (t + b)), + 'multiply' : (lambda t, b: t * b), + 'divide' : (lambda t, b: t / b if b > 0 else 0 ), + 'divide_inv': (lambda t, b: b / t if t > 0 else 0 ), + 'screen' : (lambda t, b: 1.0 - (1.0-t)*(1.0-b) ), + 'lighten' : (lambda t, b: t * (t > b) + b * (t <= b)), + 'darken' : (lambda t, b: t * (t < b) + b * (t >= b)), + 'overlay' : (lambda t, b: \ + 2.0 * t * b if t > 0.5 else \ + 1.0 - (2.0 * (1.0-t) * (1.0-b))) + } + + self.name = config.get_name().split()[1] + + self.autoStart = config.getboolean('autostart', False) + self.runOnShutown = config.getboolean('run_on_error', False) + self.heater = config.get('heater', None) + self.hot = config.get('hot', None) + self.analogPin = config.get('analog_pin', None) + self.buttonPins = config.getlist('button_pins', None) + self.stepper = config.get('stepper', None) + self.recalculate = config.get('recalculate', False) + self.endstops = [x.strip() for x in config.get('endstops','').split(',')] + self.layerTempl = self.gcode_macro.load_template(config, 'layers') + self.configLayers = [] + self.configLeds = config.get('leds') + + self.nextEventTime = 0 + self.printer.register_event_handler('klippy:ready', self._handle_ready) + self.gcode.register_mux_command('SET_LED_EFFECT', 'EFFECT', self.name, + self.cmd_SET_LED_EFFECT, + desc=self.cmd_SET_LED_help) + + if self.analogPin: + ppins = self.printer.lookup_object('pins') + self.mcu_adc = ppins.setup_pin('adc', self.analogPin) + self.mcu_adc.setup_adc_sample(ANALOG_SAMPLE_TIME, ANALOG_SAMPLE_COUNT) + self.mcu_adc.setup_adc_callback(ANALOG_REPORT_TIME, self.adcCallback) + query_adc = self.printer.load_object(self.config, 'query_adc') + query_adc.register_adc(self.name, self.mcu_adc) + + if self.buttonPins: + buttons = self.printer.load_object(config, "buttons") + buttons.register_buttons(self.buttonPins, self.button_callback) + + cmd_SET_LED_help = 'Starts or Stops the specified led_effect' + + def _handle_ready(self): + self.configChains = self.configLeds.split('\n') + self.ledChains = [] + self.leds = [] + self.enabled = self.autoStart + if not self.enabled: + self.nextEventTime = self.handler.reactor.NEVER + self.printer.register_event_handler('klippy:shutdown', + self._handle_shutdown) + #map each LED from the chains to the "pixels" in the effect frame + for chain in self.configChains: + chainName, ledIndices = self.handler.parse_chain(chain) + if chainName is not None: + ledChain = self.printer.lookup_object(chainName) + + #Add each discrete chain to the collection + if ledChain not in self.ledChains: + self.ledChains.append(ledChain) + + if ledIndices == [] : + for i in range(ledChain.led_helper.led_count): + self.leds.append((ledChain, int(i))) + else: + for led in ledIndices: + self.leds.append((ledChain, led)) + + self.ledCount = len(self.leds) + self.frame = [0.0] * COLORS * self.ledCount + + #enumerate all effects from the subclasses of _layerBase... + self.availableLayers = {str(c).rpartition('.layer')[2]\ + .replace("'>", "")\ + .lower() : c + for c in self._layerBase.__subclasses__() + if str(c).startswith("<class")} + self._generateLayers() + + def _generateLayers(self, context=None): + self.layers = [] + if context is None: + context = self.gcode_macro.create_template_context() + context.update({'params': {}, 'rawparams': ''}) + self.configLayers = self.layerTempl.render(context) + for layer in [line for line \ + in self.configLayers.split('\n') if line.strip()]: + + parms = [parameter.strip() for parameter \ + in layer.split() if parameter.strip()] + + if not parms[0] in self.availableLayers: + raise self.printer\ + .config_error("LED Effect '%s' in section '%s' is not a " \ + "valid effect layer" % (parms[0], self.name)) + + if not parms[3] in self.blendingModes: + raise self.printer.config_error("Blending mode '%s' in section " + "'%s' is not a valid blending mode"\ + % (parms[3], self.name)) + + layer = self.availableLayers[parms[0]] + + pad = lambda x: x + [0.0] * (COLORS - len(x)) + convert = lambda s: float(s) + + try: + palette="".join(parms[4:]) # join all elements of the list + palette="".join(palette.split()) # remove whitespaces + palette=palette.strip(",") + palette=palette.split("),(") # split colors + palette=[c.split(",") for c in palette] # split color components + palette=[[convert(k.strip("()")) for k in c] for c in palette] # convert to float + for i in palette: + if len(i) > COLORS: + raise Exception( + "Color %s has too many elements." % (str(i),)) + palette=[pad(c) for c in palette] # pad to COLORS colors + palette=[k for c in palette for k in c] # flatten list + except Exception as e: + raise self.printer.config_error( + "Error parsing palette in '%s' for layer \"%s\": %s"\ + % (self.config.get_name(), parms[0], e,)) + self.layers.insert(0, layer(handler = self, + frameHandler = self.handler, + effectRate = float(parms[1]), + effectCutoff = float(parms[2]), + paletteColors = palette, + frameRate = self.frameRate, + ledCount = len(self.leds), + blendingMode = parms[3])) + + self.handler.addEffect(self) + + def getFrame(self, eventtime): + if not self.enabled and self.fadeValue <= 0.0: + if self.nextEventTime < self.handler.reactor.NEVER: + # Effect has just been disabled. Set colors to 0 and update once. + self.nextEventTime = self.handler.reactor.NEVER + self.frame = [0.0] * COLORS * self.ledCount + update = True + else: + update = False + else: + update = True + if eventtime >= self.nextEventTime: + self.nextEventTime = eventtime + self.frameRate + + self.frame = [0.0] * COLORS * self.ledCount + for layer in self.layers: + layerFrame = layer.nextFrame(eventtime) + + if layerFrame: + blend = self.blendingModes[layer.blendingMode] + self.frame = [blend(t, b) for t, b in zip(layerFrame, self.frame)] + + if (self.fadeEndTime > eventtime) and (self.fadeTime > 0.0): + remainingFade = ((self.fadeEndTime - eventtime) / self.fadeTime) + else: + remainingFade = 0.0 + + self.fadeValue = 1.0-remainingFade if self.enabled else remainingFade + + return self.frame, update + + def set_enabled(self, state): + if self.enabled != state: + self.enabled = state + self.nextEventTime = self.handler.reactor.NOW + self.handler._getFrames(self.handler.reactor.NOW) + + def reset_frame(self): + for layer in self.layers: + layer.frameNumber = 0 + + def set_fade_time(self, fadetime): + self.fadeTime = fadetime + self.fadeEndTime = self.handler.reactor.monotonic() + fadetime + if self.fadeTime == 0.0: + self.fadeValue = 0.0 + + def cmd_SET_LED_EFFECT(self, gcmd): + parmFadeTime = gcmd.get_float('FADETIME', 0.0) + + if gcmd.get_int('STOP', 0) >= 1: + if self.enabled: + self.set_fade_time(parmFadeTime) + self.set_enabled(False) + else: + if self.recalculate: + kwargs = self.layerTempl.create_template_context() + kwargs['params'] = gcmd.get_command_parameters() + kwargs['rawparams'] = gcmd.get_raw_command_parameters() + self._generateLayers(kwargs) + if gcmd.get_int('REPLACE',0) >= 1: + for led in self.leds: + for effect in self.handler.effects: + if effect is not self and led in effect.leds: + if effect.enabled: + effect.set_fade_time(parmFadeTime) + effect.set_enabled(False) + + if not self.enabled: + self.set_fade_time(parmFadeTime) + if gcmd.get_int('RESTART', 0) >= 1: + self.reset_frame() + self.set_enabled(True) + + def _handle_shutdown(self): + self.set_enabled(self.runOnShutown) + + def adcCallback(self, read_time, read_value): + self.analogValue = int(read_value * 1000.0) / 10.0 + + def button_callback(self, eventtime, state): + self.button_state = state + + ###################################################################### + # LED Effect layers + ###################################################################### + + # super class for effect animations. new animations should + # inherit this and return 1 frame of [r, g, b] * <number of leds> + # per call of nextFrame() + class _layerBase(object): + def __init__(self, **kwargs): + self.handler = kwargs['handler'] + self.frameHandler = kwargs['frameHandler'] + self.ledCount = kwargs['ledCount'] + self.paletteColors = colorArray(COLORS, kwargs['paletteColors']) + self.effectRate = kwargs['effectRate'] + self.effectCutoff = kwargs['effectCutoff'] + self.frameRate = kwargs['frameRate'] + self.blendingMode = kwargs['blendingMode'] + self.frameNumber = 0 + self.thisFrame = [] + self.frameCount = 1 + self.lastAnalog = 0 + + def nextFrame(self, eventtime): + if not self.frameCount: + return [0] * COLORS * self.ledCount + self.frameNumber += 1 + self.frameNumber = self.frameNumber * \ + ( self.frameNumber < self.frameCount ) + self.lastFrameTime = eventtime + + return self.thisFrame[self.frameNumber] + + def _decayTable(self, factor=1, rate=1): + + frame = [] + + p = (1.0 / self.frameRate) + r = (p/15.0)*factor + + for s in range(0, int((rate<1)+rate)): + frame.append(1.0) + for x in range(2, int(p / rate)): + b = exp(1)**-(x/r) + if b>.004: + frame.append(b) + return frame + + def _gradient(self, palette, steps, reverse=False, toFirst=False): + palette = colorArray(COLORS, palette[:]) + if reverse: palette.reverse() + + if len(palette) == 1: + return colorArray(COLORS, palette * steps) + + if toFirst: + palette += palette[0] + + paletteIntervals = len(palette)-1 + stepIntervals = steps if toFirst else steps-1 + if stepIntervals != 0: + intervals_per_step = float(paletteIntervals) / stepIntervals + else: + intervals_per_step = 0 + + gradient=palette[0] + + for i in range(1,steps): + j = intervals_per_step * i + k = int(j) + r = j-k + k = min(k, len(palette)-1) + + if ( (k+1) >= len(palette) ) | (r == 0.0) : + z = palette[k] + else: + z = [((1-r)*palette[k][m] + r*palette[k+1][m]) for m in range(COLORS)] + gradient += z + return gradient + + #Individual effects inherit from the LED Effect Base class + #each effect must support the nextFrame() method either by + #using the method from the base class or overriding it. + + #Solid color + class layerStatic(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerStatic, self).__init__(**kwargs) + + self.paletteColors = colorArray(COLORS, self.paletteColors) + + gradientLength = int(self.ledCount) + gradient = colorArray(COLORS, self._gradient(self.paletteColors, + gradientLength)) + + self.thisFrame.append(gradient[0:self.ledCount]) + self.frameCount = len(self.thisFrame) + + #Slow pulsing of color + class layerBreathing(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerBreathing, self).__init__(**kwargs) + + brightness = [] + + p = (1 / self.frameRate) * (self.effectRate * 0.5) + o = int(p) + f = 2 * pi + + for x in range(0, int(p)): + if x < p: + v = (exp(-cos((f / p) * (x+o)))-0.367879) / 2.35040238 + else: + v = 0 + + #clamp values + if v > 1.0: + v = 1.0 + elif v < 0.0: + v = 0.0 + + brightness.append(v) + + for c in range(0, len(self.paletteColors)): + color = self.paletteColors[c] + + for b in brightness: + self.thisFrame += [[b * i for i in color] * self.ledCount] + + self.frameCount = len(self.thisFrame) + class layerLinearFade(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerLinearFade, self).__init__(**kwargs) + + gradientLength = int(self.effectRate / self.frameRate) + if gradientLength == 0: gradientLength = 1 + + gradient = colorArray(COLORS, self._gradient(self.paletteColors, + gradientLength, toFirst=True)) + + for i in range(gradientLength): + self.thisFrame.append(gradient[i]*self.ledCount) + + self.frameCount = len(self.thisFrame) + + #Turns the entire strip on and off + class layerBlink(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerBlink, self).__init__(**kwargs) + + dutyCycle= max(0,min(1.0, self.effectCutoff)) + frameCountOn = int(( 1.0 / self.frameRate ) * self.effectRate\ + * dutyCycle) + frameCountOff = int(( 1.0 / self.frameRate ) * self.effectRate\ + * (1-dutyCycle)) + + for c in range(0, len(self.paletteColors)): + color = self.paletteColors[c] + self.thisFrame += [color * self.ledCount] * frameCountOn + self.thisFrame += [[0]*COLORS * self.ledCount] * frameCountOff + + self.frameCount = len(self.thisFrame) + + #Random flashes with decay + class layerTwinkle(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerTwinkle, self).__init__(**kwargs) + + self.thisFrame = colorArray(COLORS, ([0.0]*COLORS) * self.ledCount) + self.lastBrightness = [-1] * self.ledCount + self.decayTable = self._decayTable(factor=1 / self.effectCutoff) + self.decayLen = len(self.decayTable) + self.colorCount = len(self.paletteColors) - 1 + + def nextFrame(self, eventtime): + + for i in range(0, self.ledCount): + + r = randint(0, self.colorCount) + color = self.paletteColors[r] + + if randint(0, 255) > 254 - self.effectRate: + self.lastBrightness[i] = 0 + self.thisFrame[i] = color + + if self.lastBrightness[i] != -1: + if self.lastBrightness[i] == self.decayLen: + self.lastBrightness[i] = -1 + self.thisFrame[i] = ([0.0]*COLORS) + else: + x = self.lastBrightness[i] + self.lastBrightness[i] += 1 + self.thisFrame[i] = [self.decayTable[x] * l + for l in self.thisFrame[i]] + + return self.thisFrame + + #Blinking with decay + class layerStrobe(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerStrobe, self).__init__(**kwargs) + + frameRate = int(1.0 / self.frameRate) + if self.effectRate==0: + frameCount = 1 + else: + frameCount = max(1,int(frameRate / self.effectRate)) + if self.effectCutoff==0: self.effectCutoff=0.001 + decayTable = self._decayTable(factor=1 / self.effectCutoff, + rate=1) + if len(decayTable) > frameCount: + decayTable = decayTable[:frameCount] + else: + decayTable += [0.0] * (frameCount - len(decayTable)) + + for c in range(0, len(self.paletteColors)): + color = self.paletteColors[c] + + for b in decayTable: + self.thisFrame += [[b * i for i in color] * self.ledCount] + + self.frameCount = len(self.thisFrame) + + #Lights move sequentially with decay + class layerComet(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerComet, self).__init__(**kwargs) + if self.effectRate > 0: + self.direction = True + else: + self.direction = False + self.effectRate *= -1 + + if self.effectCutoff <= 0: self.effectCutoff = .1 + + decayTable = self._decayTable(factor=len(self.paletteColors) * \ + self.effectCutoff, rate=1) + + gradient = self.paletteColors[0] + \ + self._gradient(self.paletteColors[1:], len(decayTable)+1) + + decayTable = [c for b in zip(decayTable, decayTable, decayTable, decayTable) \ + for c in b] + + comet = colorArray(COLORS, [a * b for a, b in zip(gradient,decayTable)]) + + comet.padRight([0.0]*COLORS, self.ledCount - len(comet)) + + if self.direction: comet.reverse() + else: comet.shift(self.ledCount - len(comet)) + + if self.effectRate == 0: + self.thisFrame.append(comet[0:self.ledCount]) + else: + for i in range(len(comet)): + comet.shift(int(self.effectRate+(self.effectRate < 1)), + self.direction) + self.thisFrame.append(comet[:self.ledCount]) + + for x in range(int((1/self.effectRate)-(self.effectRate <= 1))): + self.thisFrame.append(comet[:self.ledCount]) + + self.frameCount = len(self.thisFrame) + + #Lights move sequentially with decay + class layerChase(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerChase, self).__init__(**kwargs) + + if self.effectRate > 0: + self.direction = True + else: + self.direction = False + self.effectRate *= -1 + + if len(self.paletteColors) == 1: + self.paletteColors += colorArray(COLORS,COLORS*[0]) + + decayTable = self._decayTable(factor=len(self.paletteColors) * \ + self.effectCutoff, rate=1) + + gradient = self.paletteColors[0] + \ + self._gradient(self.paletteColors[1:], len(decayTable)+1) + + decayTable = [c for b in zip(decayTable, decayTable, decayTable, decayTable) \ + for c in b] + gradient = colorArray(COLORS, [a * b + for a, b in zip(gradient,decayTable)]) + + k=int(self.ledCount/len(gradient))+1 + chase = colorArray(COLORS,k*gradient) + + if self.direction: chase.reverse() + if self.effectRate == 0: + self.thisFrame.append(chase[0:self.ledCount]) + else: + for _ in range(len(chase)): + chase.shift(int(self.effectRate+(self.effectRate < 1)), + self.direction) + self.thisFrame.append(chase[0:self.ledCount]) + + for _ in range(int((1/self.effectRate)-(self.effectRate <= 1))): + self.thisFrame.append(chase[0:self.ledCount]) + + self.frameCount = len(self.thisFrame) + + #Color gradient over all LEDs + class layerGradient(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerGradient, self).__init__(**kwargs) + + direction = -1 if self.effectRate < 0 else 1 + + if self.effectRate == 0: + gradientLength = self.ledCount + else: + gradientLength=abs(int(1/(self.effectRate * self.frameRate))) + gradient = colorArray(COLORS, self._gradient(self.paletteColors, + gradientLength, + toFirst=True)) + + for i in range(gradientLength if self.effectRate != 0 else 1): + frame = colorArray(COLORS, ([0.0]*COLORS) * self.ledCount) + for led in range(self.ledCount): + frame[led] = gradient[ int(i*direction + \ + self.effectCutoff * gradientLength * led \ + / self.ledCount ) % gradientLength] + self.thisFrame.append(frame) + + self.frameCount = len(self.thisFrame) + + class layerPattern(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerPattern, self).__init__(**kwargs) + + self.paletteColors = colorArray(COLORS, self.paletteColors) + frame = colorArray(COLORS, []) + + for i in range(int(self.ledCount/len(self.paletteColors))+1): + frame+=(self.paletteColors) + + if int(self.effectRate/self.frameRate) == 0: + self.thisFrame.append(frame) + else: + for _ in range(len(self.paletteColors) * (self.ledCount-1)): + for _ in range(int(self.effectRate/self.frameRate)): + self.thisFrame.append(colorArray(COLORS, frame)[:COLORS*self.ledCount]) + frame.shift(int(self.effectCutoff)) + + self.frameCount = len(self.thisFrame) + + #Responds to heater temperature + class layerHeater(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerHeater, self).__init__(**kwargs) + + if len(self.paletteColors) == 1: + self.paletteColors += self.paletteColors + + gradient = colorArray(COLORS, self._gradient(self.paletteColors[:-1], 200) + + self.paletteColors[-1:]) + + for i in range(len(gradient)): + self.thisFrame.append(gradient[i] * self.ledCount) + + self.frameCount = len(self.thisFrame) + + if self.handler.heater is None: + raise self.handler.printer.config_error( + "LED Effect '%s' has no heater defined." % (self.handler.name)) + + def nextFrame(self, eventtime): + heaterTarget = self.frameHandler.heaterTarget[self.handler.heater] + heaterCurrent = self.frameHandler.heaterCurrent[self.handler.heater] + heaterLast = self.frameHandler.heaterLast[self.handler.heater] + + if heaterTarget > 0.0 and heaterCurrent > 0.0: + if (heaterCurrent >= self.effectRate): + if (heaterCurrent <= heaterTarget-2): + s = int(((heaterCurrent - self.effectRate) / heaterTarget) * 200) + s = min(len(self.thisFrame)-1,s) + return self.thisFrame[s] + elif self.effectCutoff > 0: + return None + else: + return self.thisFrame[-1] + else: + return None + + elif self.effectRate > 0 and heaterCurrent > 0.0: + if heaterCurrent >= self.effectRate and heaterLast > 0: + s = int(((heaterCurrent - self.effectRate) / heaterLast) * 200) + s = min(len(self.thisFrame)-1,s) + return self.thisFrame[s] + + return None + + #Responds to heater temperature + class layerTemperature(_layerBase): + def __init__(self, **kwargs): + + super(ledEffect.layerTemperature, self).__init__(**kwargs) + if len(self.paletteColors) == 1: + self.paletteColors = colorArray(COLORS, ([0.0]*COLORS)) + self.paletteColors + gradient = colorArray(COLORS, self._gradient(self.paletteColors, 200)) + for i in range(len(gradient)): + self.thisFrame.append(gradient[i] * self.ledCount) + self.frameCount = len(self.thisFrame) + + if self.handler.heater is None: + raise self.handler.printer.config_error( + "LED Effect '%s' has no heater defined." % (self.handler.name)) + + def nextFrame(self, eventtime): + if self.effectCutoff == self.effectRate: + s = 200 if self.frameHandler.heaterCurrent[self.handler.heater] >= self.effectRate else 0 + else: + s = int(((self.frameHandler.heaterCurrent[self.handler.heater] - + self.effectRate) / + (self.effectCutoff - self.effectRate)) * 200) + + s = min(len(self.thisFrame)-1,s) + s = max(0,s) + return self.thisFrame[s] + class layerHeaterGauge(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerHeaterGauge, self).__init__(**kwargs) + + if self.effectRate < 0: + self.effectRate = self.ledCount + + if self.effectCutoff < 0: + self.effectCutoff = self.ledCount + + if self.effectRate == 0: + trailing = colorArray(COLORS, [0.0]*COLORS * self.ledCount) + else: + trailing = colorArray(COLORS, self._gradient(self.paletteColors[1:], + int(self.effectRate), True)) + trailing.padLeft([0.0]*COLORS, self.ledCount) + + if self.effectCutoff == 0: + leading = colorArray(COLORS, [0.0]*COLORS * self.ledCount) + else: + leading = colorArray(COLORS, self._gradient(self.paletteColors[1:], + int(self.effectCutoff), False)) + leading.padRight([0.0]*COLORS, self.ledCount) + + gradient = colorArray(COLORS, trailing + self.paletteColors[0] + leading) + gradient.shift(len(trailing), 0) + frames = [gradient[:self.ledCount]] + + for i in range(0, self.ledCount): + gradient.shift(1,1) + frames.append(gradient[:self.ledCount]) + + self.thisFrame.append(colorArray(COLORS, [0.0]*COLORS * self.ledCount)) + for i in range(1, 101): + x = int((i / 101.0) * self.ledCount) + self.thisFrame.append(frames[x]) + + self.frameCount = len(self.thisFrame) + + def nextFrame(self, eventtime): + heaterTarget = self.frameHandler.heaterTarget[self.handler.heater] + heaterCurrent = self.frameHandler.heaterCurrent[self.handler.heater] + heaterLast = self.frameHandler.heaterLast[self.handler.heater] + + if heaterTarget > 0.0: + p = int(heaterCurrent/heaterTarget * 100.0) + elif heaterLast > 0.0: + p = int(heaterCurrent/heaterLast * 100.0) + else: + p = 0 + + p = min(len(self.thisFrame)-1,p) + p = max(0,p) + + return self.thisFrame[p] + + class layerTemperatureGauge(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerTemperatureGauge, self).__init__(**kwargs) + + trailing = colorArray(COLORS, self._gradient(self.paletteColors[1:], + int(self.ledCount), True)) + trailing.padLeft([0.0]*COLORS, self.ledCount) + + leading = colorArray(COLORS, [0.0]*COLORS * self.ledCount) + + gradient = colorArray(COLORS, trailing + self.paletteColors[0] + leading) + gradient.shift(len(trailing), 0) + frames = [gradient[:self.ledCount]] + + for i in range(0, self.ledCount): + gradient.shift(1,1) + frames.append(gradient[:self.ledCount]) + + self.thisFrame.append(colorArray(COLORS, [0.0]*COLORS * self.ledCount)) + self.steps = 255 + for i in range(1, self.steps + 1): + x = int((i / float(self.steps + 1)) * self.ledCount) + frames2=colorArray(COLORS,[]) + + for idx,led in enumerate(frames[x]): + + brightness = min(1.0,max(0.0,len(frames[x]) * (float(i) / float(self.steps + 1)) - int(idx/COLORS))) + + frames2.append(led*brightness) + + self.thisFrame.append(frames2) + + self.frameCount = len(self.thisFrame) + + def nextFrame(self, eventtime): + if self.effectCutoff == self.effectRate: + s = len(self.thisFrame) if self.frameHandler.heaterCurrent[self.handler.heater] >= self.effectRate else 0 + else: + s = int(((self.frameHandler.heaterCurrent[self.handler.heater] - + self.effectRate) / + (self.effectCutoff - self.effectRate)) * self.steps) + + s = min(len(self.thisFrame)-1,s) + s = max(0,s) + + + + return self.thisFrame[s] + + + #Responds to analog pin voltage + class layerAnalogPin(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerAnalogPin, self).__init__(**kwargs) + + if len(self.paletteColors) == 1: + self.paletteColors = [0.0]*COLORS + self.paletteColors + + gradient = colorArray(COLORS, self._gradient(self.paletteColors, 101)) + + for i in range(len(gradient)): + self.thisFrame.append(gradient[i] * self.ledCount) + + def nextFrame(self, eventtime): + v = int(self.handler.analogValue * self.effectRate) + + if v > 100: v = 100 + + if v > self.effectCutoff: + return self.thisFrame[v] + else: + return self.thisFrame[0] + + #Lights illuminate relative to stepper position + class layerStepper(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerStepper, self).__init__(**kwargs) + + if self.effectRate < 0: + self.effectRate = self.ledCount + + if self.effectCutoff < 0: + self.effectCutoff = self.ledCount + + if self.effectRate == 0: + trailing = colorArray(COLORS, [0.0]*COLORS * self.ledCount) + else: + trailing = colorArray(COLORS, self._gradient(self.paletteColors[1:], + int(self.effectRate), True)) + trailing.padLeft([0.0]*COLORS, self.ledCount) + + if self.effectCutoff == 0: + leading = colorArray(COLORS, [0.0]*COLORS * self.ledCount) + else: + leading = colorArray(COLORS, self._gradient(self.paletteColors[1:], + int(self.effectCutoff), False)) + leading.padRight([0.0]*COLORS, self.ledCount) + + gradient = colorArray(COLORS, trailing + self.paletteColors[0] + leading) + gradient.shift(len(trailing)-1, 0) + frames = [gradient[:self.ledCount]] + + for i in range(0, self.ledCount): + gradient.shift(1,1) + frames.append(gradient[:self.ledCount]) + + for i in range(101): + x = int((i / 101.0) * self.ledCount) + self.thisFrame.append(frames[x]) + + self.frameCount = len(self.thisFrame) + + def nextFrame(self, eventtime): + if self.handler.stepper == 'x': axis = 0 + elif self.handler.stepper == 'y': axis = 1 + else: axis = 2 + + p = self.frameHandler.stepperPositions[int(axis)] + + if p < 0 : p=0 + if p > 100 : p=100 + return self.thisFrame[int((p - 1) * (p > 0))] + + class layerStepperColor(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerStepperColor, self).__init__(**kwargs) + + if len(self.paletteColors) == 1: + self.paletteColors = [0.0]*COLORS + self.paletteColors + + gradient = colorArray(COLORS, self._gradient(self.paletteColors, 101)) + + for i in range(len(gradient)): + self.thisFrame.append(gradient[i] * self.ledCount) + + def nextFrame(self, eventtime): + if self.handler.stepper == 'x': axis = 0 + elif self.handler.stepper == 'y': axis = 1 + else: axis = 2 + + p = self.frameHandler.stepperPositions[int(axis)]*self.effectRate+self.effectCutoff + + if p < 0 : p=0 + if p > 100 : p=100 + + return self.thisFrame[int(p)] + + #Shameless port of Fire2012 by Mark Kriegsman + + #Shamelessly appropriated from the Arduino FastLED example files + #Fire2012.ino by Daniel Garcia + class layerFire(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerFire, self).__init__(**kwargs) + + self.heatMap = [0.0] * self.ledCount + self.gradient = colorArray(COLORS, self._gradient(self.paletteColors, + 102)) + self.frameLen = len(self.gradient) + self.heatLen = len(self.heatMap) + self.heatSource = int(self.ledCount / 10.0) + self.effectRate = int(self.effectRate) + + if self.heatSource < 1: + self.heatSource = 1 + + def nextFrame(self, eventtime): + frame = [] + + for h in range(self.heatLen): + c = randint(0,self.effectCutoff) + self.heatMap[h] -= (self.heatMap[h] - c >= 0 ) * c + + for i in range(self.ledCount - 1, self.heatSource, -1): + d = (self.heatMap[i - 1] + + self.heatMap[i - 2] + + self.heatMap[i - 3] ) / 3 + + self.heatMap[i] = d * (d >= 0) + + if randint(0, 100) < self.effectRate: + h = randint(0, self.heatSource) + self.heatMap[h] += randint(90,100) + if self.heatMap[h] > 100: + self.heatMap[h] = 100 + + for h in self.heatMap: + frame += self.gradient[int(h)] + + return frame + + #Fire that responds relative to actual vs target temp + class layerHeaterFire(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerHeaterFire, self).__init__(**kwargs) + + self.heatMap = [0.0] * self.ledCount + self.gradient = colorArray(COLORS, self._gradient(self.paletteColors, + 102)) + self.frameLen = len(self.gradient) + self.heatLen = len(self.heatMap) + self.heatSource = int(self.ledCount / 10.0) + + if self.handler.heater is None: + raise self.handler.printer.config_error( + "LED Effect '%s' has no heater defined." % (self.handler.name)) + + if self.heatSource < 1: + self.heatSource = 1 + + def nextFrame(self, eventtime): + frame = [] + spark = 0 + heaterTarget = self.frameHandler.heaterTarget[self.handler.heater] + heaterCurrent = self.frameHandler.heaterCurrent[self.handler.heater] + heaterLast = self.frameHandler.heaterLast[self.handler.heater] + + if heaterTarget > 0.0 and heaterCurrent > 0.0: + if (heaterCurrent >= self.effectRate): + if heaterCurrent <= heaterTarget-2: + spark = int((heaterCurrent / heaterTarget) * 80) + brightness = int((heaterCurrent / heaterTarget) * 100) + elif self.effectCutoff > 0: + spark = 0 + else: + spark = 80 + brightness = 100 + elif self.effectRate > 0 and heaterCurrent > 0.0: + if heaterCurrent >= self.effectRate: + spark = int(((heaterCurrent - self.effectRate) + / heaterLast) * 80) + brightness = int(((heaterCurrent - self.effectRate) + / heaterLast) * 100) + + if spark > 0 and heaterTarget != 0: + cooling = int((heaterCurrent / heaterTarget) * 20) + + for h in range(self.heatLen): + c = randint(0, cooling) + self.heatMap[h] -= (self.heatMap[h] - c >= 0 ) * c + + for i in range(self.ledCount - 1, self.heatSource, -1): + d = (self.heatMap[i - 1] + + self.heatMap[i - 2] + + self.heatMap[i - 3] ) / 3 + + self.heatMap[i] = d * (d >= 0) + + if randint(0, 100) < spark: + h = randint(0, self.heatSource) + self.heatMap[h] += brightness + if self.heatMap[h] > 100: + self.heatMap[h] = 100 + + for h in self.heatMap: + frame += self.gradient[int(h)] + + return frame + + else: + return None + + #Progress bar using M73 gcode command + class layerProgress(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerProgress, self).__init__(**kwargs) + + if self.effectRate < 0: + self.effectRate = self.ledCount + + if self.effectCutoff < 0: + self.effectCutoff = self.ledCount + + if self.effectRate == 0: + trailing = colorArray(COLORS, [0.0]*COLORS * self.ledCount) + else: + trailing = colorArray(COLORS, self._gradient(self.paletteColors[1:], + int(self.effectRate), True)) + trailing.padLeft([0.0]*COLORS, self.ledCount) + + if self.effectCutoff == 0: + leading = colorArray(COLORS, [0.0]*COLORS * self.ledCount) + else: + leading = colorArray(COLORS, self._gradient(self.paletteColors[1:], + int(self.effectCutoff), False)) + leading.padRight([0.0]*COLORS, self.ledCount) + + gradient = colorArray(COLORS, trailing + self.paletteColors[0] + leading) + gradient.shift(len(trailing), 0) + frames = [gradient[:self.ledCount]] + + for i in range(0, self.ledCount): + gradient.shift(1,1) + frames.append(gradient[:self.ledCount]) + + self.thisFrame.append(colorArray(COLORS, [0.0]*COLORS * self.ledCount)) + for i in range(1, 101): + x = int((i / 101.0) * self.ledCount) + self.thisFrame.append(frames[x]) + + self.frameCount = len(self.thisFrame) + + def nextFrame(self, eventtime): + p = self.frameHandler.printProgress + return self.thisFrame[p] #(p - 1) * (p > 0)] + + class layerStatus(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerStatus, self).__init__(**kwargs) + if self.handler.hot is None: + raise self.handler.printer.config_error( + "LED Effect '%s' has no heater defined." % (self.handler.name)) + def nextFrame(self, eventtime): + hotTarget = max(self.frameHandler.hotTarget.values()) + p = self.frameHandler.runStatus + msg = self.frameHandler.runtStatusMsg + if p == 'standby': + color_index = 1 if hotTarget > 0 else 0 + elif p == 'printing': + color_index = 1 + elif p == 'paused': + color_index = 2 + elif p == 'cancelled': + if msg == '': + color_index = 0 + else: + color_index = 2 + elif p == 'error': + color_index = 2 + else: + color_index = 0 + return self.paletteColors[color_index] + + class layerHoming(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerHoming, self).__init__(**kwargs) + + self.paletteColors = colorArray(COLORS, self.paletteColors) + + gradientLength = int(self.ledCount) + gradient = colorArray(COLORS, self._gradient(self.paletteColors, + gradientLength)) + + for c in range(0, len(self.paletteColors)): + color = self.paletteColors[c] + self.thisFrame.append(colorArray(COLORS,color*self.ledCount)) + + self.decayTable = self._decayTable(factor=self.effectRate) + self.decayTable.append(0.0) + self.decayLen = len(self.decayTable) + self.counter=self.decayLen-1 + self.coloridx=-1 + self.my_flag={} + for endstop in self.handler.endstops: + self.frameHandler.homing_end_flag[endstop] = 0 + self.my_flag[endstop] = self.frameHandler.homing_end_flag[endstop] + + def nextFrame(self, eventtime): + for endstop in self.handler.endstops: + + if self.my_flag[endstop] != self.frameHandler.homing_end_flag[endstop]: + self.counter = 0 + self.coloridx = (self.coloridx + 1) % len(self.paletteColors) + self.my_flag[endstop] = self.frameHandler.homing_end_flag[endstop] + + frame = [self.decayTable[self.counter] * i for i in self.thisFrame[self.coloridx ]] + if self.counter < self.decayLen-1: + self.counter += 1 + + return frame + class layerSwitchButton(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerSwitchButton, self).__init__(**kwargs) + self.last_state = 0 + self.coloridx = 0 + self.fadeValue = 0.0 + self.paletteColors = colorArray(COLORS, self.paletteColors) + + for c in range(0, len(self.paletteColors)): + color = self.paletteColors[c] + self.thisFrame.append(colorArray(COLORS,color*self.ledCount)) + + def nextFrame(self, eventtime): + if self.handler.button_state > self.last_state: + self.coloridx = (self.coloridx + 1) % len(self.paletteColors) + + self.last_state = self.handler.button_state + + if self.last_state: + if self.effectRate > 0 and self.fadeValue < 1.0: + self.fadeValue += (self.handler.frameRate / self.effectRate) + else: + self.fadeValue = 1.0 + else: + if self.effectCutoff > 0 and self.fadeValue > 0.0: + self.fadeValue -= (self.handler.frameRate / self.effectCutoff) + else: + self.fadeValue = 0.0 + + if self.fadeValue < 0: self.fadeValue = 0 + if self.fadeValue > 1.0: self.fadeValue = 1.0 + return [self.fadeValue * i for i in self.thisFrame[self.coloridx]] + + class layerToggleButton(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerToggleButton, self).__init__(**kwargs) + self.last_state = 0 + self.last_coloridx = 0 + self.coloridx = 0 + self.fadeInValue = 0.0 + self.fadeOutValue = 0.0 + self.active = False + self.paletteColors = colorArray(COLORS, self.paletteColors) + + for c in range(0, len(self.paletteColors)): + color = self.paletteColors[c] + self.thisFrame.append(colorArray(COLORS,color*self.ledCount)) + + def nextFrame(self, eventtime): + if self.handler.button_state > self.last_state: + self.last_coloridx = self.coloridx + self.coloridx = (self.coloridx + 1) % len(self.paletteColors) + self.last_state = self.handler.button_state + self.fadeInValue = 0 + self.fadeOutValue = 1.0 + + self.last_state = self.handler.button_state + + if self.effectRate > 0 and self.fadeInValue < 1.0: + self.fadeInValue += (self.handler.frameRate / self.effectRate) + else: + self.fadeInValue = 1.0 + if self.effectCutoff > 0 and self.fadeOutValue > 0.0: + self.fadeOutValue -= (self.handler.frameRate / self.effectCutoff) + else: + self.fadeOutValue = 0.0 + + if self.fadeInValue < 0: self.fadeInValue = 0 + if self.fadeInValue > 1.0: self.fadeInValue = 1.0 + + if self.fadeOutValue < 0: self.fadeOutValue = 0 + if self.fadeOutValue > 1.0: self.fadeOutValue = 1.0 + + frameIn = [self.fadeInValue * i for i in self.thisFrame[self.coloridx]] + frameOut = [self.fadeOutValue * i for i in self.thisFrame[self.last_coloridx]] + + return [ i + o for i, o in zip(frameIn,frameOut)] + + class layerFlashButton(_layerBase): + def __init__(self, **kwargs): + super(ledEffect.layerFlashButton, self).__init__(**kwargs) + self.last_state = 0 + self.active = False + self.coloridx = 0 + self.fadeValue = 0.0 + self.paletteColors = colorArray(COLORS, self.paletteColors) + + for c in range(0, len(self.paletteColors)): + color = self.paletteColors[c] + self.thisFrame.append(colorArray(COLORS,color*self.ledCount)) + + def nextFrame(self, eventtime): + + if self.handler.button_state > self.last_state: + self.coloridx = (self.coloridx + 1) % len(self.paletteColors) + self.active = True + + self.last_state=self.handler.button_state + + if self.active: + if self.effectRate > 0 and self.fadeValue < 1.0: + self.fadeValue += (self.handler.frameRate / self.effectRate) + else: + self.fadeValue = 1.0 + if self.fadeValue >= 1.0: + self.fadeValue = 1.0 + self.active = False + else: + if self.effectCutoff > 0 and self.fadeValue > 0.0: + self.fadeValue -= (self.handler.frameRate / self.effectCutoff) + else: + self.fadeValue = 0.0 + + if self.fadeValue <= 0: + self.fadeValue = 0 + + return [self.fadeValue * i for i in self.thisFrame[self.coloridx]] + +def load_config_prefix(config): + return ledEffect(config) \ No newline at end of file diff --git a/klippy/extras/print_stats.py b/klippy/extras/print_stats.py index 668cd7d0c..0044dc3c9 100644 --- a/klippy/extras/print_stats.py +++ b/klippy/extras/print_stats.py @@ -53,10 +53,10 @@ class PrintStats: def note_cancel(self): self._note_finish("cancelled") def _note_finish(self, state, error_message = ""): + self.error_message = error_message if self.print_start_time is None: return self.state = state - self.error_message = error_message eventtime = self.reactor.monotonic() self.total_duration = eventtime - self.print_start_time if self.filament_used < 0.0000001: