LEDs: nozzle light follows the motion sensor, new logo status macro

The motion timeout switched the nozzle LEDs off during prints, motion
switched them off when idle or paused, the timeout counted from the first
movement, and every _status_* macro stopped the nozzle light.

- _LIGHTS sets case light and nozzle LEDs from presence, print state and
  CASELIGHT MODE=AUTO|ON|OFF; the timeout (60 s) starts at the sensor
  release
- _STATUS STATE=... replaces the _status_* macros; logo effects only
  cover the logo LEDs and use REPLACE=1
- heater gauge while heating, print progress, paused, error flash from
  _ERROR, part ready once the bed is cool, dim night mode when idle and
  nobody near, cleaning during BLOBIFIER_CLEAN
- removed unused effects and macros, 12 fps for the toolhead effects

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mangavalkandClaude Opus 5.5 committed 2026-10-17 19:32:42 +02:00
1 parent fbdb2d5e1d
commit e5be65834e
8 files changed
+286 -291

No files matched your search

+166 -248
View File
@@ -1,216 +1,191 @@
# Stealthburner LEDs: logo status effects (_STATUS) and the nozzle light
#
# Based on the Rainbow Barf logo LED effects by tanaes:
# https://github.com/tanaes/whopping_Voron_mods/blob/main/LEDs/Rainbow_Barf_Logo_LED/Code/stealthburner_led_effects_barf.cfg
# Macros for setting the status leds on the Voron StealthBurner toolhead (or for any neopixel-type leds).
# which builds on the Voron Stealthburner LED macros. Needs klipper-led_effect.
#
# You will need to configure a neopixel (or other addressable led, such as dotstar). See
# https://www.klipper3d.org/Config_Reference.html#neopixel for configuration details.
#####################################
# INSTRUCTIONS #
#####################################
# How to use all this stuff:
# sb_leds 1-8 are the logo, 9-10 the nozzle LEDs. The logo shows the printer
# status (_STATUS); the nozzle LEDs are white while someone is near the
# printer (sensors/motion_sensor.cfg). led_effect adds up effects that share
# an LED, so the logo effects only cover 1-8 and never stop the nozzle light.
#
# 1. Copy this .cfg file into your Klipper config directory and then add [include stealthburner_leds.cfg]
# to the top of your printer.cfg in order for register the LEDs and macros with Klipper.
# 2. Define your LEDs by editing [neopixel sb_leds] below and entering the data pin from your control board
# as well as the color order.
# _STATUS STATE=<state> set and show a status
# _STATUS show the current status again
# _STATUS_SHOW STATE=... show a status without storing it (cleaning)
# _STATUS_FLASH STATE=... show a status for a while (_ERROR: error)
#
# Note: RGB and RGBW are different and must be defined explicitly. RGB and RGBW are also not able to
# be mix-and-matched in the same chain. A separate data line would be needed for proper functioning.
#
# RGBW LEDs will have a visible yellow-ish phosphor section to the chip. If your LEDs do not have
# this yellow portion, you have RGB LEDs.
#
# 3. Save your config and restart Klipper.
#
# Note: We set RED and BLUE to 1.0 to make it easier for users and supporters to detect
# misconfigurations or miswiring. The default color format is for Neopixels with a dedicated
# white LED. On startup, all three SB LEDs should light up.
#
# If you get random colors across your LEDs, change the color_order to GRB and restart. Then
# omit the W for each suggested color_order in the next paragraph.
#
# If you get MAGENTA, your color order is correct. If you get CYAN, you need to use RGBW. If
# you get YELLOW, you need to use BRGW (note that BRG is only supported in the latest Klipper
# version).
#
# 4. Once you have confirmed that the LEDs are set up correctly, you must now decide where you want
# these macros called up...which means adding them to your existing gcode macros. NOTHING will happen
# unless you add the STATUS_????? macros to your existing gcode macros.
#
# Example: add STATUS_LEVELING to the beginning of your QGL gcode macro, and then add STATUS_READY
# to the end of it to set the logo LED and nozzle LEDs back to the `ready` state.
#
# Example: add STATUS_CLEANING to the beginning of your nozzle-cleaning macro, and then STATUS_READY
# to the end of it to return the LEDs back to `ready` state.
#
# 5. Feel free to change colors of each macro, create new ones if you have a need to. The macros provided below
# are just an example of what is possible. If you want to try some more complex animations, you will most
# likely have to use WLED with Moonraker and a small micro-controller (please see the LED thread for help inside
# of the stealthburner_beta channel on Discord).
#
#####################################
# END INSTRUCTRUCTIONS #
#####################################
# States: ready, homing, heating_bed, heating_extruder, calibrating_z,
# leveling, meshing, cleaning, printing, paused, part_ready, error.
# ready: rainbow while someone is near, dim (logo and Box Turtle
# logo) when nobody is near
# heating_*: the logo fills up with the temperature towards the target
# printing: the logo fills up with the print progress
# part_ready: blue while the bed is above part_ready_temp, then green
[neopixel sb_leds]
pin: nhk:PD3
# The pin connected to the neopixel. This parameter must be provided.
chain_count: 10
# The number of Neopixel chips that are "daisy chained" to the
# provided pin. The default is 1 (which indicates only a single
# Neopixel is connected to the pin).
# color_order: GRB, GRB, GRB, GRB, GRB, GRB, GRB, GRB, GRBW, GRBW
color_order: GRB, GRB, GRB, GRB, GRB, GRB, GRB, GRB, GRB, GRB
# Set the pixel order required by the LED hardware. Options are GRB,
# RGB, GRBW, or RGBW. The default is GRB.
color_order: GRB, GRB, GRB, GRB, GRB, GRB, GRB, GRB, GRB, GRB
# Magenta until the first effect starts: shows that the chain and the
# colour order are right
initial_RED: 1.0
initial_GREEN: 0.0
initial_BLUE: 1.0
initial_WHITE: 0.0
# Sets the initial LED color of the Neopixel. Each value should be
# between 0.0 and 1.0. The WHITE option is only available on RGBW
# LEDs. The default for each color is 0.#
##########################
# LED Effects Animations #
##########################
# led_effect sends the whole chain at the rate of the fastest effect running
# on it, so all sb_leds effects use 12 fps.
##################
## logo effects ##
##################
[led_effect sb_logo_busy]
[led_effect sb_logo_ready]
autostart: false
frame_rate: 24
frame_rate: 12
leds:
neopixel:sb_leds (2,1,3,4,5,6,7,8)
layers:
breathing 3 1 top (1,0,0)
gradient 0.3 1 add (0.3, 0.0, 0.0),(0.0, 0.3, 0.0),(0.0, 0.0, 0.3)
[led_effect sb_logo_cleaning]
[led_effect sb_logo_night]
autostart: false
frame_rate: 24
frame_rate: 12
leds:
neopixel:sb_leds (2,1,3,4,5,6,7,8)
layers:
breathing 3 1 top (0.0, 0.02, 0.5)
static 0 0 top (0.02, 0.02, 0.02)
[led_effect sb_logo_calibrating_z]
[led_effect bt_logo_night]
autostart: false
frame_rate: 24
frame_rate: 10
leds:
neopixel:sb_leds (2,1,3,4,5,6,7,8)
neopixel:bt_logo
layers:
breathing 3 1 top (0.0, 0.0, 0.35)
[led_effect sb_logo_heating]
leds:
neopixel:sb_leds (2,3,7,8,6,1)
autostart: false
frame_rate: 24
layers:
comet 0.3 0 add (1, 0.18, 0)
[led_effect sb_logo_cooling]
leds:
neopixel:sb_leds (2,3,7,8,6,1)
autostart: false
frame_rate: 24
layers:
comet 0.3 0 add (0, 0, 1)
static 0 0 top (0.02, 0.02, 0.02)
[led_effect sb_logo_homing]
autostart: false
frame_rate: 24
frame_rate: 12
leds:
neopixel:sb_leds (2,1,3,4,5,6,7,8)
layers:
breathing 3 1 top (0.0, 0.6, 0.2)
breathing 3 1 top (0.0, 0.6, 0.2)
# heatergauge: the LEDs light up one by one with temperature / target
[led_effect sb_logo_heating_bed]
autostart: false
frame_rate: 12
heater: heater_bed
leds:
neopixel:sb_leds (2,1,3,4,5,6,7,8)
layers:
heatergauge -1 0 add (1.0, 0.18, 0.0),(1.0, 0.18, 0.0)
static 0 0 top (0.08, 0.015, 0.0)
[led_effect sb_logo_heating_extruder]
autostart: false
frame_rate: 12
heater: extruder
leds:
neopixel:sb_leds (2,1,3,4,5,6,7,8)
layers:
heatergauge -1 0 add (1.0, 0.0, 0.0),(1.0, 0.0, 0.0)
static 0 0 top (0.08, 0.0, 0.0)
[led_effect sb_logo_calibrating_z]
autostart: false
frame_rate: 12
leds:
neopixel:sb_leds (2,1,3,4,5,6,7,8)
layers:
breathing 3 1 top (0.0, 0.0, 0.35)
[led_effect sb_logo_leveling]
autostart: false
frame_rate: 24
frame_rate: 12
leds:
neopixel:sb_leds (2,1,3,4,5,6,7,8)
layers:
breathing 3 1 top (0.5, 0.1, 0.4)
breathing 3 1 top (0.5, 0.1, 0.4)
[led_effect sb_logo_meshing]
autostart: false
frame_rate: 24
frame_rate: 12
leds:
neopixel:sb_leds (2,1,3,4,5,6,7,8)
layers:
breathing 3 1 top (0.2, 1.0, 0.0)
breathing 3 1 top (0.2, 1.0, 0.0)
[led_effect sb_logo_cleaning]
autostart: false
frame_rate: 12
leds:
neopixel:sb_leds (2,1,3,4,5,6,7,8)
layers:
breathing 3 1 top (0.0, 0.02, 0.5)
# progress: the LEDs light up one by one with the print progress
# (display_status: M73 from the slicer, else the file position)
[led_effect sb_logo_printing]
autostart: false
frame_rate: 24
frame_rate: 12
leds:
neopixel:sb_leds (2,1,3,4,5,6,7,8)
layers:
gradient 0.3 1 add (0.3, 0.0, 0.0),(0.3, 0.3, 0.0),(0.3, 0.1, 0.0)
progress -1 0 add (0.3, 0.3, 0.3),(0.3, 0.3, 0.3)
static 0 0 top (0.08, 0.02, 0.0)
[led_effect sb_logo_standby]
[led_effect sb_logo_paused]
autostart: false
frame_rate: 24
frame_rate: 12
leds:
neopixel:sb_leds (2,1,3,4,5,6,7,8)
layers:
breathing 3 1 top (0.01, 0.01, 0.01)
breathing 2 1 top (1.0, 0.35, 0.0)
[led_effect sb_logo_cooling]
autostart: false
frame_rate: 12
leds:
neopixel:sb_leds (2,1,3,4,5,6,7,8)
layers:
breathing 3 1 top (0.0, 0.0, 1.0)
[led_effect sb_logo_part_ready]
autostart: false
frame_rate: 24
frame_rate: 12
leds:
neopixel:sb_leds (2,1,3,4,5,6,7,8)
layers:
breathing 3 1 top (0.0, 1.0, 0.0)
breathing 3 1 top (0.0, 1.0, 0.0)
####################
## nozzle effects ##
####################
[led_effect sb_nozzle_heating]
[led_effect sb_logo_error]
autostart: false
frame_rate: 24
frame_rate: 12
leds:
neopixel:sb_leds (2,1,3,4,5,6,7,8)
layers:
blink 1 0.5 top (1.0, 0.0, 0.0)
###################
## nozzle effect ##
###################
# Switched by _LIGHTS (sensors/motion_sensor.cfg)
[led_effect sb_nozzle_light]
autostart: false
frame_rate: 12
leds:
neopixel:sb_leds (9,10)
layers:
breathing 3 1 top (1.0, 0.18, 0.0, 0.0)
[led_effect sb_nozzle_cooling]
autostart: false
frame_rate: 24
leds:
neopixel:sb_leds (9,10)
layers:
breathing 3 1 top (0.0, 0.0, 1.0, 0.1)
[led_effect sb_nozzle_standby]
autostart: false
frame_rate: 24
leds:
neopixel:sb_leds (9,10)
layers:
breathing 3 1 top (0.6, 0.0, 0.0, 0.0)
[led_effect sb_nozzle_part_ready]
autostart: false
frame_rate: 24
leds:
neopixel:sb_leds (9,10)
layers:
breathing 3 1 top (0.6, 1.0, 0.0, 0.1)
static 0 0 top (1.0, 1.0, 1.0)
#####################
## all led effects ##
#####################
# Klipper shutdown
[led_effect sb_critical_error]
leds:
neopixel:sb_leds
@@ -222,129 +197,72 @@ autostart: false
frame_rate: 24
run_on_error: true
[led_effect rainbow]
leds:
neopixel:sb_leds
autostart: true
frame_rate: 24
layers:
gradient 0.3 1 add (0.3, 0.0, 0.0),(0.0, 0.3, 0.0),(0.0, 0.0, 0.3)
#######################
# LED Effects Statics #
#######################
[led_effect set_nozzle_leds]
leds:
neopixel:sb_leds (9,10)
#neopixel:caselight
autostart: false
frame_rate: 24
layers:
# static 0 0 top (0.0, 0.0, 0.0, 1.0)
static 0 0 top (1.0, 1.0, 1.0, 1.0)
[led_effect set_logo_leds]
leds:
neopixel:sb_leds (2,1,3,4,5,6,7,8)
#neopixel:caselight
autostart: false
frame_rate: 24
layers:
static 0 0 top (1.0, 1.0, 1.0)
##############
# The Macros #
##############
[gcode_macro _set_logo_leds_off]
[gcode_macro _STATUS]
description: Set the logo status (STATE=ready, homing, heating_bed, ...); without STATE show the current one again
variable_state: 'ready'
variable_part_ready_temp: 35 # part_ready: blue until the bed is below this (C), then green
variable_fade_time: 0.5 # s cross-fade between effects (logo and nozzle light)
gcode:
SET_LED_EFFECT EFFECT=set_logo_leds STOP=1
{% set new = params.STATE|default(state)|lower %}
{% if new != state %}
SET_GCODE_VARIABLE MACRO=_STATUS VARIABLE=state VALUE="'{new}'"
{% endif %}
_STATUS_SHOW STATE={new}
[gcode_macro _set_logo_leds_on]
[gcode_macro _STATUS_SHOW]
description: Show STATE on the logo without storing it as the current status
gcode:
SET_LED_EFFECT EFFECT=set_logo_leds
{% set state = params.STATE|lower %}
{% set cfg = printer['gcode_macro _STATUS'] %}
{% set near = printer['gcode_macro _LIGHTS'].near if 'gcode_macro _LIGHTS' in printer else True %}
{% set night = state == 'ready' and not near %}
{% set cool = printer.heater_bed.temperature < cfg.part_ready_temp %}
{% if state == 'ready' %}
{% set effect = 'sb_logo_night' if night else 'sb_logo_ready' %}
{% elif state == 'part_ready' %}
{% set effect = 'sb_logo_part_ready' if cool else 'sb_logo_cooling' %}
{% else %}
{% set effect = 'sb_logo_' ~ state %}
{% endif %}
{% if ('led_effect ' ~ effect) in printer %}
# REPLACE: stops the other effects on the logo LEDs, not the nozzle light
SET_LED_EFFECT EFFECT={effect} REPLACE=1 FADETIME={cfg.fade_time}
SET_LED_EFFECT EFFECT={'bt_logo_night' if night else 'rainbow_turtle'} REPLACE=1 FADETIME={cfg.fade_time}
{% else %}
_WARN MSG="_STATUS: unknown state {state}"
{% endif %}
{% if state == 'part_ready' and not cool %}
UPDATE_DELAYED_GCODE ID=_status_part_ready_check DURATION=30
{% endif %}
[gcode_macro _set_nozzle_leds_on]
[delayed_gcode _status_part_ready_check]
gcode:
SET_LED_EFFECT EFFECT=set_nozzle_leds
{% if printer['gcode_macro _STATUS'].state == 'part_ready' %}
_STATUS
{% endif %}
[gcode_macro _set_nozzle_leds_off]
[gcode_macro _STATUS_FLASH]
description: Show STATE on the logo for DURATION seconds (default 10), then the current status again
gcode:
SET_LED_EFFECT EFFECT=set_nozzle_leds STOP=1
_STATUS_SHOW STATE={params.STATE}
UPDATE_DELAYED_GCODE ID=_status_flash_end DURATION={params.DURATION|default(10)|float}
# The _status_* macros only stop the toolhead effects (neopixel:sb_leds), so
# the Box Turtle logo (rainbow_turtle on neopixel:bt_logo) keeps running during
# prints. _status_off still stops everything; _status_ready starts the logo again.
[gcode_macro _status_off]
# After an error that ended the print (print_stats: error) the logo stays red
# until the next status (next print, CANCEL_PRINT, idle timeout)
[delayed_gcode _status_flash_end]
gcode:
STOP_LED_EFFECTS
{% set state = printer['gcode_macro _STATUS'].state %}
{% if printer.print_stats.state == 'error' and state not in ['ready', 'part_ready'] %}
_STATUS STATE=error
{% else %}
_STATUS
{% endif %}
[gcode_macro _status_ready]
[delayed_gcode _status_startup]
initial_duration: 1
gcode:
STOP_LED_EFFECTS LEDS="neopixel:sb_leds"
SET_LED_EFFECT EFFECT=rainbow
SET_LED_EFFECT EFFECT=rainbow_turtle
[gcode_macro _status_part_ready]
gcode:
STOP_LED_EFFECTS LEDS="neopixel:sb_leds"
SET_LED_EFFECT EFFECT=sb_nozzle_part_ready
SET_LED_EFFECT EFFECT=sb_logo_part_ready
[gcode_macro _status_busy]
gcode:
STOP_LED_EFFECTS LEDS="neopixel:sb_leds"
SET_LED_EFFECT EFFECT=sb_logo_busy
_set_nozzle_leds_on
[gcode_macro _status_heating]
gcode:
STOP_LED_EFFECTS LEDS="neopixel:sb_leds"
SET_LED_EFFECT EFFECT=sb_logo_heating
SET_LED_EFFECT EFFECT=sb_nozzle_heating
[gcode_macro _status_cooling]
gcode:
STOP_LED_EFFECTS LEDS="neopixel:sb_leds"
SET_LED_EFFECT EFFECT=sb_logo_cooling
SET_LED_EFFECT EFFECT=sb_nozzle_cooling
[gcode_macro _status_leveling]
gcode:
STOP_LED_EFFECTS LEDS="neopixel:sb_leds"
SET_LED_EFFECT EFFECT=sb_logo_leveling
_set_nozzle_leds_on
[gcode_macro _status_homing]
gcode:
STOP_LED_EFFECTS LEDS="neopixel:sb_leds"
SET_LED_EFFECT EFFECT=sb_logo_homing
_set_nozzle_leds_on
[gcode_macro _status_cleaning]
gcode:
STOP_LED_EFFECTS LEDS="neopixel:sb_leds"
SET_LED_EFFECT EFFECT=sb_logo_cleaning
_set_nozzle_leds_on
[gcode_macro _status_meshing]
gcode:
STOP_LED_EFFECTS LEDS="neopixel:sb_leds"
SET_LED_EFFECT EFFECT=sb_logo_meshing
_set_nozzle_leds_on
[gcode_macro _status_calibrating_z]
gcode:
STOP_LED_EFFECTS LEDS="neopixel:sb_leds"
SET_LED_EFFECT EFFECT=sb_logo_calibrating_z
_set_nozzle_leds_on
[gcode_macro _status_printing]
gcode:
STOP_LED_EFFECTS LEDS="neopixel:sb_leds"
SET_LED_EFFECT EFFECT=sb_logo_printing
_set_nozzle_leds_on
_STATUS STATE=ready