diff --git a/adafruit_led_animation/animation/__init__.py b/adafruit_led_animation/animation/__init__.py index 5265296..c7ec84d 100644 --- a/adafruit_led_animation/animation/__init__.py +++ b/adafruit_led_animation/animation/__init__.py @@ -68,7 +68,7 @@ def __init__(self, pixel_object, speed, color, peers=None, paused=False, name=No self._time_left_at_pause = 0 self._also_notify = [] self.speed = speed # sets _speed_ns - self.color = color # Triggers _recompute_color + self.color = color # Triggers _set_color self.name = name self.cycle_complete = False self.notify_cycles = 1 @@ -173,6 +173,7 @@ def fill(self, color): Fills the pixel object with a color. """ self.pixel_object.fill(color) + self.pixel_object.show() @property def color(self): @@ -187,8 +188,14 @@ def color(self, color): return if isinstance(color, int): color = (color >> 16 & 0xFF, color >> 8 & 0xFF, color & 0xFF) + self._set_color(color) + + def _set_color(self, color): + """ + Called after the color is changed, which includes at initialization. + Override as needed. + """ self._color = color - self._recompute_color(color) @property def speed(self): @@ -201,12 +208,6 @@ def speed(self): def speed(self, seconds): self._speed_ns = int(seconds * NANOS_PER_SECOND) - def _recompute_color(self, color): - """ - Called if the color is changed, which includes at initialization. - Override as needed. - """ - def on_cycle_complete(self): """ Called by some animations when they complete an animation cycle. diff --git a/adafruit_led_animation/animation/blink.py b/adafruit_led_animation/animation/blink.py index fe6ec10..8d482f8 100644 --- a/adafruit_led_animation/animation/blink.py +++ b/adafruit_led_animation/animation/blink.py @@ -60,5 +60,5 @@ class Blink(ColorCycle): def __init__(self, pixel_object, speed, color, name=None): super().__init__(pixel_object, speed, [color, BLACK], name=name) - def _recompute_color(self, color): + def _set_color(self, color): self.colors = [color, BLACK] diff --git a/adafruit_led_animation/animation/comet.py b/adafruit_led_animation/animation/comet.py index bbe54e7..85e36d2 100644 --- a/adafruit_led_animation/animation/comet.py +++ b/adafruit_led_animation/animation/comet.py @@ -92,10 +92,7 @@ def __init__( on_cycle_complete_supported = True - def _recompute_color(self, color): - self._comet_recompute_color(color) - - def _comet_recompute_color(self, color): + def _set_color(self, color): self._comet_colors = [BLACK] for n in range(self._tail_length): self._comet_colors.append( diff --git a/adafruit_led_animation/animation/customcolorchase.py b/adafruit_led_animation/animation/customcolorchase.py new file mode 100644 index 0000000..7defcb6 --- /dev/null +++ b/adafruit_led_animation/animation/customcolorchase.py @@ -0,0 +1,85 @@ +# The MIT License (MIT) +# +# Copyright (c) 2019-2020 Roy Hooper +# Copyright (c) 2020 Kattni Rembor for Adafruit Industries +# Copyright (c) 2020 Connie Sieh +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +""" +`adafruit_led_animation.animation.customcolorchase` +================================================================================ + +Custom color chase animation for CircuitPython helper library for LED animations. + +* Author(s): Roy Hooper, Kattni Rembor, Connie Sieh + +Implementation Notes +-------------------- + +**Hardware:** + +* `Adafruit NeoPixels `_ +* `Adafruit DotStars `_ + +**Software and Dependencies:** + +* Adafruit CircuitPython firmware for the supported boards: + https://circuitpython.org/downloads + + +""" + +from adafruit_led_animation.animation.chase import Chase +from adafruit_led_animation.color import RAINBOW + + +class CustomColorChase(Chase): + """ + Chase pixels in one direction, like a theater marquee with Custom Colors + + :param pixel_object: The initialised LED object. + :param float speed: Animation speed rate in seconds, e.g. ``0.1``. + :param colors: Animation colors in list of `(r, g, b)`` tuple, or ``0x000000`` hex format + :param size: Number of pixels to turn on in a row. + :param spacing: Number of pixels to turn off in a row. + :param reverse: Reverse direction of movement. + """ + + # pylint: disable=too-many-arguments + def __init__( + self, + pixel_object, + speed, + size=2, + spacing=3, + reverse=False, + name=None, + colors=RAINBOW, + ): + self._num_colors = len(colors) + self._colors = colors + self._color_idx = 0 + super().__init__(pixel_object, speed, 0, size, spacing, reverse, name) + + def bar_color(self, n, pixel_no=0): + return self._colors[self._color_idx - (n % len(self._colors))] + + def on_cycle_complete(self): + self._color_idx = (self._color_idx + self._direction) % len(self._colors) + super().on_cycle_complete() diff --git a/adafruit_led_animation/animation/rainbowcomet.py b/adafruit_led_animation/animation/rainbowcomet.py index 572f859..3cc84bf 100644 --- a/adafruit_led_animation/animation/rainbowcomet.py +++ b/adafruit_led_animation/animation/rainbowcomet.py @@ -82,7 +82,7 @@ def __init__( self._colorwheel_offset = colorwheel_offset super().__init__(pixel_object, speed, 0, tail_length, reverse, bounce, name) - def _comet_recompute_color(self, color): + def _set_color(self, color): self._comet_colors = [BLACK] for n in range(self._tail_length): invert = self._tail_length - n - 1 diff --git a/adafruit_led_animation/animation/solid.py b/adafruit_led_animation/animation/solid.py index 7fa90e6..497fff3 100644 --- a/adafruit_led_animation/animation/solid.py +++ b/adafruit_led_animation/animation/solid.py @@ -58,5 +58,5 @@ class Solid(ColorCycle): def __init__(self, pixel_object, color, name=None): super().__init__(pixel_object, speed=1, colors=[color], name=name) - def _recompute_color(self, color): + def _set_color(self, color): self.colors = [color] diff --git a/adafruit_led_animation/animation/sparkle.py b/adafruit_led_animation/animation/sparkle.py index 8f0e691..b975f24 100644 --- a/adafruit_led_animation/animation/sparkle.py +++ b/adafruit_led_animation/animation/sparkle.py @@ -71,7 +71,7 @@ def __init__(self, pixel_object, speed, color, num_sparkles=1, name=None): self._pixels = [] super().__init__(pixel_object, speed, color, name=name) - def _recompute_color(self, color): + def _set_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)): diff --git a/adafruit_led_animation/animation/sparklepulse.py b/adafruit_led_animation/animation/sparklepulse.py index 8e41bf2..9a06848 100644 --- a/adafruit_led_animation/animation/sparklepulse.py +++ b/adafruit_led_animation/animation/sparklepulse.py @@ -80,6 +80,9 @@ def __init__( ) self._generator = pulse_generator(self._period, self, dotstar_pwm=dotstar) + def _set_color(self, color): + self._color = color + def draw(self): self._sparkle_color = next(self._generator) super().draw() diff --git a/adafruit_led_animation/group.py b/adafruit_led_animation/group.py index 0005170..a036a03 100644 --- a/adafruit_led_animation/group.py +++ b/adafruit_led_animation/group.py @@ -47,6 +47,8 @@ __version__ = "0.0.0-auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_LED_Animation.git" +from adafruit_led_animation.animation import Animation + class AnimationGroup: """ @@ -158,7 +160,14 @@ def animate(self, show=True): if self._sync: result = self._members[0].animate(show=False) if result and show: - self._members[0].show() + last_strip = None + for member in self._members: + if isinstance(member, Animation): + if last_strip != member.pixel_object: + member.pixel_object.show() + last_strip = member.pixel_object + else: + member.show() return result return any([item.animate(show) for item in self._members]) diff --git a/adafruit_led_animation/sequence.py b/adafruit_led_animation/sequence.py index f1aba9c..bdf8eff 100644 --- a/adafruit_led_animation/sequence.py +++ b/adafruit_led_animation/sequence.py @@ -172,7 +172,6 @@ def _advance(self): self.current_animation.reset() if self.auto_clear: self.current_animation.fill(self.clear_color) - self.current_animation.show() if self._random: self.random() else: @@ -317,6 +316,6 @@ def on_cycle_complete(self): super().on_cycle_complete() self._running = False - def animate(self): - super().animate() + def animate(self, show=True): + super().animate(show) return self._running diff --git a/examples/led_animation_all_animations.py b/examples/led_animation_all_animations.py index 16a82bd..5eb8287 100644 --- a/examples/led_animation_all_animations.py +++ b/examples/led_animation_all_animations.py @@ -21,6 +21,7 @@ from adafruit_led_animation.animation.solid import Solid from adafruit_led_animation.animation.colorcycle import ColorCycle from adafruit_led_animation.animation.rainbow import Rainbow +from adafruit_led_animation.animation.customcolorchase import CustomColorChase from adafruit_led_animation.sequence import AnimationSequence from adafruit_led_animation.color import PURPLE, WHITE, AMBER, JADE, MAGENTA, ORANGE @@ -43,6 +44,9 @@ rainbow_comet = RainbowComet(pixels, speed=0.1, tail_length=7, bounce=True) rainbow_chase = RainbowChase(pixels, speed=0.1, size=3, spacing=2, step=8) rainbow_sparkle = RainbowSparkle(pixels, speed=0.1, num_sparkles=15) +custom_color_chase = CustomColorChase( + pixels, speed=0.1, size=2, spacing=3, colors=[ORANGE, WHITE, JADE] +) animations = AnimationSequence( @@ -57,6 +61,7 @@ rainbow_comet, sparkle_pulse, rainbow_chase, + custom_color_chase, advance_interval=5, auto_clear=True, ) diff --git a/examples/led_animation_customcolorchase.py b/examples/led_animation_customcolorchase.py new file mode 100644 index 0000000..bc9d891 --- /dev/null +++ b/examples/led_animation_customcolorchase.py @@ -0,0 +1,66 @@ +""" +This example displays custom color chase animations in sequence, at a six second interval. + +For NeoPixel FeatherWing. Update pixel_pin and pixel_num to match your wiring if using +a different form of NeoPixels. + +This example may not work on SAMD21 (M0) boards. +""" +import board +import neopixel + +from adafruit_led_animation.animation.customcolorchase import CustomColorChase +from adafruit_led_animation.sequence import AnimationSequence + +# colorwheel only needed for rainbowchase example +from adafruit_led_animation.color import colorwheel + +# Colors for customcolorchase examples +from adafruit_led_animation.color import PINK, GREEN, RED, BLUE + +# Update to match the pin connected to your NeoPixels +pixel_pin = board.D5 +# Update to match the number of NeoPixels you have connected +pixel_num = 30 +brightness = 0.3 + +pixels = neopixel.NeoPixel( + pixel_pin, pixel_num, brightness=brightness, auto_write=False +) + +# colors default to RAINBOW as defined in color.py +custom_color_chase_rainbow = CustomColorChase(pixels, speed=0.1, size=2, spacing=3) +custom_color_chase_rainbow_r = CustomColorChase( + pixels, speed=0.1, size=3, spacing=3, reverse=True +) + +# Example with same colors as RainbowChase +steps = 30 +# This was taken from rainbowchase.py +rainbow_colors = [colorwheel(n % 256) for n in range(0, 512, steps)] +# Now use rainbow_colors with CustomColorChase +custom_color_chase_rainbowchase = CustomColorChase( + pixels, speed=0.1, colors=rainbow_colors, size=2, spacing=3 +) + +custom_color_chase_bgp = CustomColorChase( + pixels, speed=0.1, colors=[BLUE, GREEN, PINK], size=3, spacing=2 +) + +# Can use integer values for color, 0 is black +custom_color_chase_br = CustomColorChase( + pixels, speed=0.1, colors=[BLUE, 0, RED, 0], size=2, spacing=0 +) + +animations = AnimationSequence( + custom_color_chase_rainbow, + custom_color_chase_rainbow_r, + custom_color_chase_rainbowchase, + custom_color_chase_bgp, + custom_color_chase_br, + advance_interval=6, + auto_clear=True, +) + +while True: + animations.animate()