chase.py
1 # SPDX-FileCopyrightText: 2020 Kattni Rembor for Adafruit Industries 2 # 3 # SPDX-License-Identifier: MIT 4 5 """ 6 `adafruit_led_animation.animation.chase` 7 ================================================================================ 8 9 Theatre chase animation for CircuitPython helper library for LED animations. 10 11 * Author(s): Kattni Rembor 12 13 Implementation Notes 14 -------------------- 15 16 **Hardware:** 17 18 * `Adafruit NeoPixels <https://www.adafruit.com/category/168>`_ 19 * `Adafruit DotStars <https://www.adafruit.com/category/885>`_ 20 21 **Software and Dependencies:** 22 23 * Adafruit CircuitPython firmware for the supported boards: 24 https://circuitpython.org/downloads 25 26 27 """ 28 29 from math import ceil 30 31 from adafruit_led_animation.animation import Animation 32 33 34 class Chase(Animation): 35 """ 36 Chase pixels in one direction in a single color, like a theater marquee sign. 37 38 :param pixel_object: The initialised LED object. 39 :param float speed: Animation speed rate in seconds, e.g. ``0.1``. 40 :param color: Animation color in ``(r, g, b)`` tuple, or ``0x000000`` hex format. 41 :param size: Number of pixels to turn on in a row. 42 :param spacing: Number of pixels to turn off in a row. 43 :param reverse: Reverse direction of movement. 44 """ 45 46 # pylint: disable=too-many-arguments 47 def __init__( 48 self, pixel_object, speed, color, size=2, spacing=3, reverse=False, name=None 49 ): 50 self._size = size 51 self._spacing = spacing 52 self._repeat_width = size + spacing 53 self._num_repeats = ceil(len(pixel_object) / self._repeat_width) 54 self._overflow = len(pixel_object) % self._repeat_width 55 self._direction = 1 if not reverse else -1 56 self._reverse = reverse 57 self._offset = 0 58 59 def _resetter(): 60 self._offset = 0 61 self._reverse = reverse 62 self._direction = 1 if not reverse else -1 63 64 self._reset = _resetter 65 66 super().__init__(pixel_object, speed, color, name=name) 67 68 on_cycle_complete_supported = True 69 70 @property 71 def reverse(self): 72 """ 73 Whether the animation is reversed 74 """ 75 return self._reverse 76 77 @reverse.setter 78 def reverse(self, value): 79 self._reverse = value 80 self._direction = -1 if self._reverse else 1 81 82 def draw(self): 83 def bar_colors(): 84 bar_no = 0 85 for i in range(self._offset, 0, -1): 86 if i > self._spacing: 87 yield self.bar_color(bar_no, i) 88 else: 89 yield self.space_color(bar_no, i) 90 bar_no = 1 91 while True: 92 for bar_pixel in range(self._size): 93 yield self.bar_color(bar_no, bar_pixel) 94 for space_pixel in range(self._spacing): 95 yield self.space_color(bar_no, space_pixel) 96 bar_no += 1 97 98 colorgen = bar_colors() 99 self.pixel_object[:] = [next(colorgen) for _ in self.pixel_object] 100 101 if self.draw_count % len(self.pixel_object) == 0: 102 self.cycle_complete = True 103 self._offset = (self._offset + self._direction) % self._repeat_width 104 105 def bar_color(self, n, pixel_no=0): # pylint: disable=unused-argument 106 """ 107 Generate the color for the n'th bar_color in the Chase 108 109 :param n: The pixel group to get the color for 110 :param pixel_no: Which pixel in the group to get the color for 111 """ 112 return self.color 113 114 def space_color(self, n, pixel_no=0): # pylint: disable=unused-argument,no-self-use 115 """ 116 Generate the spacing color for the n'th bar_color in the Chase 117 118 :param n: The pixel group to get the spacing color for 119 :param pixel_no: Which pixel in the group to get the spacing color for 120 """ 121 return 0 122 123 def reset(self): 124 """ 125 Reset the animation. 126 """ 127 self._reset()