diff --git a/adafruit_led_animation/animation/pulse.py b/adafruit_led_animation/animation/pulse.py index 9f8e047..af7c0e6 100644 --- a/adafruit_led_animation/animation/pulse.py +++ b/adafruit_led_animation/animation/pulse.py @@ -68,7 +68,7 @@ class Pulse(Animation): def draw(self): color = next(self._generator) - self.fill(color) + self.pixel_object.fill(color) def reset(self): """ @@ -77,8 +77,13 @@ class Pulse(Animation): white = len(self.pixel_object[0]) > 3 and isinstance( self.pixel_object[0][-1], int ) + dotstar = len(self.pixel_object[0]) == 4 and isinstance( + self.pixel_object[0][-1], float + ) from adafruit_led_animation.helper import ( # pylint: disable=import-outside-toplevel pulse_generator, ) - self._generator = pulse_generator(self._period, self, white) + self._generator = pulse_generator( + self._period, self, white, dotstar_pwm=dotstar + ) diff --git a/adafruit_led_animation/animation/sparkle.py b/adafruit_led_animation/animation/sparkle.py index 716841b..8f0e691 100644 --- a/adafruit_led_animation/animation/sparkle.py +++ b/adafruit_led_animation/animation/sparkle.py @@ -64,9 +64,11 @@ class Sparkle(Animation): def __init__(self, pixel_object, speed, color, num_sparkles=1, name=None): if len(pixel_object) < 2: raise ValueError("Sparkle needs at least 2 pixels") - self._half_color = None - self._dim_color = None + self._half_color = color + self._dim_color = color + self._sparkle_color = color self._num_sparkles = num_sparkles + self._pixels = [] super().__init__(pixel_object, speed, color, name=name) def _recompute_color(self, color): @@ -79,15 +81,18 @@ class Sparkle(Animation): self.pixel_object[pixel] = dim_color self._half_color = half_color self._dim_color = dim_color + self._sparkle_color = color def draw(self): - pixels = [ + self._pixels = [ random.randint(0, (len(self.pixel_object) - 2)) - for n in range(self._num_sparkles) + for _ in range(self._num_sparkles) ] - for pixel in pixels: - self.pixel_object[pixel] = self._color + for pixel in self._pixels: + self.pixel_object[pixel] = self._sparkle_color + + def after_draw(self): self.show() - for pixel in pixels: + for pixel in self._pixels: self.pixel_object[pixel] = self._half_color self.pixel_object[pixel + 1] = self._dim_color diff --git a/adafruit_led_animation/animation/sparklepulse.py b/adafruit_led_animation/animation/sparklepulse.py index 4e8e9a3..b2e59b4 100644 --- a/adafruit_led_animation/animation/sparklepulse.py +++ b/adafruit_led_animation/animation/sparklepulse.py @@ -44,14 +44,13 @@ Implementation Notes """ -import random -from adafruit_led_animation import NANOS_PER_SECOND, monotonic_ns -from adafruit_led_animation.animation import Animation +from adafruit_led_animation.animation.sparkle import Sparkle +from adafruit_led_animation.helper import pulse_generator -class SparklePulse(Animation): +class SparklePulse(Sparkle): """ - Combination of the Spark and Pulse animations. + Combination of the Sparkle and Pulse animations. :param pixel_object: The initialised LED object. :param int speed: Animation refresh rate in seconds, e.g. ``0.1``. @@ -63,50 +62,30 @@ class SparklePulse(Animation): # pylint: disable=too-many-arguments def __init__( - self, pixel_object, speed, color, period=5, max_intensity=1, min_intensity=0 + self, + pixel_object, + speed, + color, + period=5, + max_intensity=1, + min_intensity=0, + name=None, ): - if len(pixel_object) < 2: - raise ValueError("Sparkle needs at least 2 pixels") - self.max_intensity = max_intensity - self.min_intensity = min_intensity + self._max_intensity = max_intensity + self._min_intensity = min_intensity self._period = period - self._intensity_delta = max_intensity - min_intensity - self._half_period = period / 2 - self._position_factor = 1 / self._half_period - self._bpp = len(pixel_object[0]) - # Handle dotstars - if self._bpp == 4 and isinstance(pixel_object[0][3], float): - self._bpp = 3 - self._last_update = monotonic_ns() - self._cycle_position = 0 - self._half_color = None - self._dim_color = None - super().__init__(pixel_object, speed, color) - - def _recompute_color(self, color): - half_color = tuple(color[rgb] // 4 for rgb in range(len(color))) - dim_color = tuple(color[rgb] // 10 for rgb in range(len(color))) - for pixel in range(len(self.pixel_object)): - if self.pixel_object[pixel] == self._half_color: - self.pixel_object[pixel] = half_color - elif self.pixel_object[pixel] == self._dim_color: - self.pixel_object[pixel] = dim_color - self._half_color = half_color - self._dim_color = dim_color + white = len(pixel_object) == 4 and isinstance(pixel_object[0][-1], int) + dotstar = len(pixel_object) == 4 and isinstance(pixel_object[0][-1], float) + super().__init__( + pixel_object, speed=speed, color=color, num_sparkles=1, name=name + ) + self._generator = pulse_generator( + self._period, self, white, dotstar_pwm=dotstar + ) def draw(self): - pixel = random.randint(0, (len(self.pixel_object) - 2)) + self._sparkle_color = next(self._generator) + super().draw() - now = monotonic_ns() - time_since_last_draw = (now - self._last_update) / NANOS_PER_SECOND - self._last_update = now - pos = self._cycle_position = ( - self._cycle_position + time_since_last_draw - ) % self._period - if pos > self._half_period: - pos = self._period - pos - intensity = self.min_intensity + ( - pos * self._intensity_delta * self._position_factor - ) - color = [int(self.color[n] * intensity) for n in range(self._bpp)] - self.pixel_object[pixel] = color + def after_draw(self): + self.show() diff --git a/adafruit_led_animation/helper.py b/adafruit_led_animation/helper.py index e37d97a..bd3d3e7 100644 --- a/adafruit_led_animation/helper.py +++ b/adafruit_led_animation/helper.py @@ -361,12 +361,13 @@ class PixelSubset: self._pixels.auto_write = value -def pulse_generator(period: float, animation_object, white=False): +def pulse_generator(period: float, animation_object, white=False, dotstar_pwm=False): """ Generates a sequence of colors for a pulse, based on the time period specified. :param period: Pulse duration in seconds. :param animation_object: An animation object to interact with. :param white: Whether the pixel strip has a white pixel. + :param dotstar_pwm: Whether to use the dostar per pixel PWM value for brightness control. """ period = int(period * NANOS_PER_SECOND) half_period = period // 2 @@ -386,6 +387,10 @@ def pulse_generator(period: float, animation_object, white=False): if pos > half_period: pos = period - pos intensity = pos / half_period + if dotstar_pwm: + fill_color = (fill_color[0], fill_color[1], fill_color[2], intensity) + yield fill_color + continue if white: fill_color[3] = int(fill_color[3] * intensity) fill_color[0] = int(fill_color[0] * intensity)