diff --git a/docs/LED_Effect.md b/docs/LED_Effect.md index 87efcb1..54eec44 100644 --- a/docs/LED_Effect.md +++ b/docs/LED_Effect.md @@ -193,22 +193,31 @@ Enable layer template recalculation on effect activation. heater: Specifies the heater to use for a heater effect. Use `extruder` for the -extruder and `heater_bed` for the bed. For temperature fans or sensors add the +extruder and `heater_bed` for the bed. For temperature fans or sensors add the type and use quotes. Example: `heater: "temperature_fan myfan"` analog_pin: Specifies the pin to use for effects using an analog signal. +Example: `analog_pin: PA1` stepper: Specifies the axis to use for the stepper effect. Possible values are: -`x`, `y` and `z`. Example: `stepper: x` +`x`, `y` and `z`. +Example: `stepper: x` endstops: Specifies the endstops the homing effect triggers on. Multiple endstops can be -specified as a comma seprated list. Possible values are: `x`, `y`, `z` and `probe`. +specified as a comma seperated list. Possible values are: `x`, `y`, `z` and `probe`. Example: `endstops: x, y` +button_pins: +Specifies the pins the button effect trigger on. Multiple pins can be specified +as a comma seperated list. Then the effect will trigger on any of the buttons. +Using already assigned pins (such as endstop pins) is possible by using +`duplicate_pin_override` (see Klipper documentation for details). +Example: `button_pins: PC1, PC2` + ## Defining LEDs The `leds:` section is a list of Neopixel or Dotstar strips that will @@ -264,8 +273,8 @@ Each layer is defined with the following parameters Each layer must be on a single line and each line must be indented. Color palettes can be of unlimited length but may be compressed depending on the size of the frame or number of LEDs on a strip. Colors are defined -as groups of Red, Green, Blue and (optional) White. The white channel only used -on RGBW LEDs and ignored on RGB LEDs. The range for each color is a decimal +as groups of Red, Green, Blue and (optional) White. The white channel is only +used on RGBW LEDs and ignored on RGB LEDs. The range for each color is a decimal number from 0.0 to 1.0. So for yellow, you would use ( 1.0, 1.0, 0.0 ). For white you would use ( 1.0, 1.0, 1.0 ) on an RGB LED or ( 0.0, 0.0, 0.0, 1.0 ) on an RGBW LED. @@ -462,9 +471,37 @@ layer reports print progress. Cutoff: 0 Not used, but must be provided Palette: Colors are cycled in order -LEDs turn on during homing when the endstop is triggered and fade out again. The -effect rate determines the time for the fade out. If a palette of multiple colors -is provided, it will cycle through those colors in order. +Needs an endstop defined. LEDs turn on during homing when the endstop is +triggered and fade out again. The effect rate determines the time for the fade +out. If a palette of multiple colors is provided, it will cycle through those +colors in order. + +#### SwitchButton + Effect Rate: 1 Fade in time. Time until LEDs are on after button press + Cutoff: 1 Fade out time. Time until LEDs are off after button release + Palette: Colors are cycled in order + +Needs a button_pin defined. LEDs turn on when the button is pressed and turn off +when the button is released again. Each press cycles through the colors of the +palette. + +#### ToggleButton + Effect Rate: 1 Fade in time. Time to fade in next color + Cutoff: 1 Fade out time. Time to fade out previous color + Palette: Colors are cycled in order + +Needs a button_pin defined. Cycles through the colors with each button press. +The transition times can be configured with the effect rate and cutoff parameters. +Hint: Define (0,0,0) as a color if you want to toggle between on and off. + +#### FlashButton + Effect Rate: 0.1 Fade in time. Time to fade in. + Cutoff: 1 Fade out time. Time to fade out. + Palette: Colors are cycled in order + +Needs a button_pin defined. When the button is pressed the LEDs fade on in the +defined time and fade off immediately afterwards. If a palette of multiple colors +is provided, it will cycle through those colors in order with each button press. ## Effect Layer Blending If you have ever used image editing software you may be familiar with diff --git a/src/led_effect.py b/src/led_effect.py index 3712f19..2ee8cd4 100644 --- a/src/led_effect.py +++ b/src/led_effect.py @@ -8,7 +8,6 @@ from math import cos, exp, pi from random import randint -import logging ANALOG_SAMPLE_TIME = 0.001 ANALOG_SAMPLE_COUNT = 5 @@ -114,7 +113,6 @@ def _handle_shutdown(self): def _handle_homing_move_begin(self, hmove): endstops_being_homed = [name for es,name in hmove.endstops] - logging.info(endstops_being_homed) for endstop in endstops_being_homed: if endstop in self.homing_start_flag: @@ -317,6 +315,7 @@ def __init__(self, config): self.iteration = 0 self.layers = [] self.analogValue = 0 + self.button_state = 0 self.fadeValue = 0.0 self.fadeTime = 0.0 self.fadeEndTime = 0 @@ -347,6 +346,7 @@ def __init__(self, config): self.runOnShutown = config.getboolean('run_on_error', False) self.heater = config.get('heater', 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(',')] @@ -368,6 +368,10 @@ def __init__(self, config): 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): @@ -541,6 +545,9 @@ def _handle_shutdown(self): 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 @@ -1243,7 +1250,6 @@ def __init__(self, **kwargs): self.coloridx=-1 self.my_flag={} for endstop in self.handler.endstops: - logging.info(endstop) self.frameHandler.homing_end_flag[endstop] = 0 self.my_flag[endstop] = self.frameHandler.homing_end_flag[endstop] @@ -1261,6 +1267,123 @@ def nextFrame(self, eventtime): 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)