diff options
author | Kevin O'Connor <kevin@koconnor.net> | 2022-03-23 12:04:42 -0400 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2022-03-31 13:08:12 -0400 |
commit | 96795def9c90276bcf3ea00d2292002237363ed6 (patch) | |
tree | 709d89c83d0728d789b6ad1e7230c24c4d30fad2 /klippy | |
parent | 3340bb2ffd23ff86a8b22e238f6c0dea85c740a2 (diff) | |
download | kutter-96795def9c90276bcf3ea00d2292002237363ed6.tar.gz kutter-96795def9c90276bcf3ea00d2292002237363ed6.tar.xz kutter-96795def9c90276bcf3ea00d2292002237363ed6.zip |
led: Add support for PWM controlled LEDs
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
Diffstat (limited to 'klippy')
-rw-r--r-- | klippy/extras/led.py | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/klippy/extras/led.py b/klippy/extras/led.py new file mode 100644 index 00000000..bfc85956 --- /dev/null +++ b/klippy/extras/led.py @@ -0,0 +1,122 @@ +# Support for PWM driven LEDs +# +# Copyright (C) 2019-2022 Kevin O'Connor <kevin@koconnor.net> +# +# This file may be distributed under the terms of the GNU GPLv3 license. +import logging + +# Helper code for common LED initialization and control +class LEDHelper: + def __init__(self, config, update_func, led_count=1, has_white=False): + self.printer = config.get_printer() + self.update_func = update_func + self.led_count = led_count + # Initial color + red = config.getfloat('initial_RED', 0., minval=0., maxval=1.) + green = config.getfloat('initial_GREEN', 0., minval=0., maxval=1.) + blue = config.getfloat('initial_BLUE', 0., minval=0., maxval=1.) + white = 0. + if has_white: + white = config.getfloat('initial_WHITE', 0., minval=0., maxval=1.) + self.led_state = [(red, green, blue, white)] * led_count + # Register commands + name = config.get_name().split()[-1] + gcode = self.printer.lookup_object('gcode') + gcode.register_mux_command("SET_LED", "LED", name, self.cmd_SET_LED, + desc=self.cmd_SET_LED_help) + cmd_SET_LED_help = "Set the color of an LED" + def cmd_SET_LED(self, gcmd): + # Parse parameters + red = gcmd.get_float('RED', 0., minval=0., maxval=1.) + green = gcmd.get_float('GREEN', 0., minval=0., maxval=1.) + blue = gcmd.get_float('BLUE', 0., minval=0., maxval=1.) + white = gcmd.get_float('WHITE', 0., minval=0., maxval=1.) + index = gcmd.get_int('INDEX', None, minval=1, maxval=self.led_count) + transmit = gcmd.get_int('TRANSMIT', 1) + sync = gcmd.get_int('SYNC', 1) + color = (red, green, blue, white) + # Update and transmit data + def lookahead_bgfunc(print_time): + if index is None: + new_led_state = [color] * self.led_count + if self.led_state == new_led_state: + return + self.led_state = new_led_state + else: + if self.led_state[index - 1] == color: + return + self.led_state = led_state = list(self.led_state) + led_state[index - 1] = color + if transmit: + try: + self.update_func(self.led_state, print_time) + except self.printer.command_error as e: + logging.exception("led update transmit error") + if sync: + #Sync LED Update with print time and send + toolhead = self.printer.lookup_object('toolhead') + toolhead.register_lookahead_callback(lookahead_bgfunc) + else: + #Send update now (so as not to wake toolhead and reset idle_timeout) + lookahead_bgfunc(None) + def get_status(self, eventtime=None): + return {'color_data': self.led_state} + +# Main LED tracking code +class PrinterLED: + def __init__(self, config): + self.printer = config.get_printer() + def setup_helper(self, config, update_func, led_count=1, has_white=False): + return LEDHelper(config, update_func, led_count, has_white) + +PIN_MIN_TIME = 0.100 +MAX_SCHEDULE_TIME = 5.0 + +# Handler for PWM controlled LEDs +class PrinterPWMLED: + def __init__(self, config): + self.printer = printer = config.get_printer() + # Configure pwm pins + ppins = printer.lookup_object('pins') + cycle_time = config.getfloat('cycle_time', 0.010, above=0., + maxval=MAX_SCHEDULE_TIME) + hardware_pwm = config.getboolean('hardware_pwm', False) + self.pins = [] + for i, name in enumerate(("red", "green", "blue", "white")): + pin_name = config.get(name + '_pin', None) + if pin_name is None: + continue + mcu_pin = ppins.setup_pin('pwm', pin_name) + mcu_pin.setup_max_duration(0.) + mcu_pin.setup_cycle_time(cycle_time, hardware_pwm) + self.pins.append((i, mcu_pin)) + if not self.pins: + raise config.error("No LED pin definitions found in '%s'" + % (config.get_name(),)) + self.last_print_time = 0. + # Initialize color data + pled = printer.load_object(config, "led") + self.led_helper = pled.setup_helper(config, self.update_leds, 1, True) + self.prev_color = color = self.led_helper.get_status()['color_data'][0] + for idx, mcu_pin in self.pins: + mcu_pin.setup_start_value(color[idx], 0.) + def update_leds(self, led_state, print_time): + if print_time is None: + eventtime = self.printer.get_reactor().monotonic() + mcu = self.pins[0][1].get_mcu() + print_time = mcu.estimated_print_time(eventtime) + PIN_MIN_TIME + print_time = max(print_time, self.last_print_time + PIN_MIN_TIME) + color = led_state[0] + for idx, mcu_pin in self.pins: + if self.prev_color[idx] != color[idx]: + mcu_pin.set_pwm(print_time, color[idx]) + self.last_print_time = print_time + self.prev_color = color + def get_status(self, eventtime=None): + return self.led_helper.get_status(eventtime) + +def load_config(config): + return PrinterLED(config) + +def load_config_prefix(config): + return PrinterPWMLED(config) |