From 968a7beed42f89a5d287ba9ca32f5096fc3cf291 Mon Sep 17 00:00:00 2001 From: Roy Hooper Date: Sun, 7 Jun 2020 13:09:11 -0400 Subject: [PATCH] simplify and clean up pixelmap, add ability to use pixel numbers without a list wrapping them --- adafruit_led_animation/animation/pulse.py | 7 +- .../animation/sparklepulse.py | 5 +- adafruit_led_animation/helper.py | 153 +++++++----------- 3 files changed, 64 insertions(+), 101 deletions(-) diff --git a/adafruit_led_animation/animation/pulse.py b/adafruit_led_animation/animation/pulse.py index af7c0e6..e788d6d 100644 --- a/adafruit_led_animation/animation/pulse.py +++ b/adafruit_led_animation/animation/pulse.py @@ -74,9 +74,6 @@ class Pulse(Animation): """ Resets the 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 ) @@ -84,6 +81,4 @@ class Pulse(Animation): pulse_generator, ) - self._generator = pulse_generator( - self._period, self, white, dotstar_pwm=dotstar - ) + self._generator = pulse_generator(self._period, self, dotstar_pwm=dotstar) diff --git a/adafruit_led_animation/animation/sparklepulse.py b/adafruit_led_animation/animation/sparklepulse.py index b2e59b4..8e41bf2 100644 --- a/adafruit_led_animation/animation/sparklepulse.py +++ b/adafruit_led_animation/animation/sparklepulse.py @@ -74,14 +74,11 @@ class SparklePulse(Sparkle): self._max_intensity = max_intensity self._min_intensity = min_intensity self._period = period - 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 - ) + self._generator = pulse_generator(self._period, self, dotstar_pwm=dotstar) def draw(self): self._sparkle_color = next(self._generator) diff --git a/adafruit_led_animation/helper.py b/adafruit_led_animation/helper.py index 255a2d0..15661dd 100644 --- a/adafruit_led_animation/helper.py +++ b/adafruit_led_animation/helper.py @@ -45,6 +45,7 @@ Implementation Notes import math from . import NANOS_PER_SECOND, monotonic_ns +from .color import calculate_intensity class PixelMap: @@ -69,7 +70,7 @@ class PixelMap: pixel_wing_horizontal[0] = (255, 255, 0) pixel_wing_horizontal.show() - To use with individual pixels: + To use with groups of individual pixels: .. code-block:: python @@ -92,24 +93,59 @@ class PixelMap: pixel_wing_vertical[0] = (255, 255, 0) pixel_wing_vertical.show() + To use with individual pixels: + + .. code-block:: python + + import board + import neopixel + import time + from adafruit_led_animation.helper import PixelMap + + pixels = neopixel.NeoPixel(board.D6, 8, auto_write=False) + + pixel_map = PixelMap(pixels, [ + 0, 7, 1, 6, 2, 5, 3, 4 + ], individual_pixels=True) + + n = 0 + while True: + pixel_map[n] = AMBER + pixel_map.show() + n = n + 1 + if n > 7: + n = 0 + pixel_map.fill(0) + time.sleep(0.25) + + """ def __init__(self, strip, pixel_ranges, individual_pixels=False): self._pixels = strip self._ranges = pixel_ranges + self.n = len(self._ranges) + if self.n == 0: + raise (ValueError("A PixelMap must have at least one pixel defined")) self._individual_pixels = individual_pixels + self._expand_ranges() + + def _expand_ranges(self): + if not self._individual_pixels: + self._ranges = [ + [n for n in range(start, end)] for start, end in self._ranges + ] + return + if isinstance(self._ranges[0], int): + self._ranges = [[n] for n in self._ranges] def __repr__(self): - return "[" + ", ".join([str(x) for x in self]) + "]" + return "[" + ", ".join([str(self[x]) for x in range(self.n)]) + "]" def _set_pixels(self, index, val): - if self._individual_pixels: - for pixel in self._ranges[index]: - self._pixels[pixel] = val - else: - range_start, range_stop = self._ranges[index] - self._pixels[range_start:range_stop] = [val] * (range_stop - range_start) + for pixel in self._ranges[index]: + self._pixels[pixel] = val def __setitem__(self, index, val): if isinstance(index, slice): @@ -124,7 +160,7 @@ class PixelMap: else: self._set_pixels(index, val) - if not self._pixels.auto_write: + if self._pixels.auto_write: self.show() def __getitem__(self, index): @@ -160,13 +196,9 @@ class PixelMap: :param color: Color to fill all pixels referenced by this PixelMap definition with. """ - if self._individual_pixels: - for pixels in self._ranges: - for pixel in pixels: - self._pixels[pixel] = color - else: - for start, stop in self._ranges: - self._pixels[start:stop] = [color] * (stop - start) + for pixels in self._ranges: + for pixel in pixels: + self._pixels[pixel] = color def show(self): """ @@ -273,7 +305,7 @@ def horizontal_strip_gridmap(width, alternating=True): return mapper -class PixelSubset: +class PixelSubset(PixelMap): """ PixelSubset lets you work with a subset of a pixel object. @@ -295,78 +327,18 @@ class PixelSubset: """ def __init__(self, pixel_object, start, end): - self._pixels = pixel_object - self._start = start - self._end = end - self.n = self._end - self._start - - def __repr__(self): - return "[" + ", ".join([str(x) for x in self]) + "]" - - def __setitem__(self, index, val): - if isinstance(index, slice): - start, stop, step = index.indices(self.n) - self._pixels[start + self._start : stop + self._start : step] = val - else: - self._pixels[index + self._start] = val - - if not self._pixels.auto_write: - self.show() - - def __getitem__(self, index): - if isinstance(index, slice): - start, stop, step = index.indices(self.n) - return self._pixels[start + self._start : stop + self._start : step] - if index < 0: - index += len(self) - if index >= self.n or index < 0: - raise IndexError - return self._pixels[index] - - def __len__(self): - return self.n - - @property - def brightness(self): - """ - brightness from the underlying strip. - """ - return self._pixels.brightness - - @brightness.setter - def brightness(self, brightness): - self._pixels.brightness = min(max(brightness, 0.0), 1.0) - - def fill(self, color): - """ - Fill the used pixel ranges with color. - """ - self._pixels[self._start : self._end] = [color] * (self.n) - - def show(self): - """ - Shows the pixels on the underlying strip. - """ - self._pixels.show() - - @property - def auto_write(self): - """ - auto_write from the underlying strip. - """ - return self._pixels.auto_write - - @auto_write.setter - def auto_write(self, value): - self._pixels.auto_write = value + super().__init__( + pixel_object, + pixel_ranges=[[n] for n in range(start, end)], + individual_pixels=True, + ) -def pulse_generator(period: float, animation_object, white=False, dotstar_pwm=False): +def pulse_generator(period: float, animation_object, 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) @@ -376,7 +348,6 @@ def pulse_generator(period: float, animation_object, white=False, dotstar_pwm=Fa cycle_position = 0 last_pos = 0 while True: - fill_color = list(animation_object.color) now = monotonic_ns() time_since_last_draw = now - last_update last_update = now @@ -388,12 +359,12 @@ def pulse_generator(period: float, animation_object, white=False, dotstar_pwm=Fa pos = period - pos intensity = pos / half_period if dotstar_pwm: - fill_color = (fill_color[0], fill_color[1], fill_color[2], intensity) + fill_color = ( + animation_object.color[0], + animation_object.color[1], + animation_object.color[2], + intensity, + ) yield fill_color continue - if white and len(fill_color) == 4: - fill_color[3] = int(fill_color[3] * intensity) - fill_color[0] = int(fill_color[0] * intensity) - fill_color[1] = int(fill_color[1] * intensity) - fill_color[2] = int(fill_color[2] * intensity) - yield fill_color + yield calculate_intensity(animation_object.color, intensity)