Skip to content

Commit cdd61d6

Browse files
committed
split library up further to help with low memory boards
1 parent 79ae49e commit cdd61d6

16 files changed

+985
-677
lines changed

adafruit_led_animation/animation.py

Lines changed: 0 additions & 504 deletions
This file was deleted.
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
# The MIT License (MIT)
2+
#
3+
# Copyright (c) 2019-2020 Roy Hooper
4+
# Copyright (c) 2020 Kattni Rembor for Adafruit Industries
5+
#
6+
# Permission is hereby granted, free of charge, to any person obtaining a copy
7+
# of this software and associated documentation files (the "Software"), to deal
8+
# in the Software without restriction, including without limitation the rights
9+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
# copies of the Software, and to permit persons to whom the Software is
11+
# furnished to do so, subject to the following conditions:
12+
#
13+
# The above copyright notice and this permission notice shall be included in
14+
# all copies or substantial portions of the Software.
15+
#
16+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
# THE SOFTWARE.
23+
"""
24+
`adafruit_led_animation.animation`
25+
================================================================================
26+
27+
Animation base class, and basic animations for CircuitPython helper library for LED animations.
28+
29+
* Author(s): Roy Hooper, Kattni Rembor
30+
31+
Implementation Notes
32+
--------------------
33+
34+
**Hardware:**
35+
36+
* `Adafruit NeoPixels <https://www.adafruit.com/category/168>`_
37+
* `Adafruit DotStars <https://www.adafruit.com/category/885>`_
38+
39+
**Software and Dependencies:**
40+
41+
* Adafruit CircuitPython firmware for the supported boards:
42+
https://circuitpython.org/downloads
43+
44+
"""
45+
46+
__version__ = "0.0.0-auto.0"
47+
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_LED_Animation.git"
48+
49+
from time import monotonic_ns
50+
51+
from adafruit_led_animation import NANOS_PER_SECOND
52+
53+
54+
class Animation:
55+
# pylint: disable=too-many-instance-attributes
56+
"""
57+
Base class for animations.
58+
"""
59+
cycle_complete_supported = False
60+
61+
# pylint: disable=too-many-arguments
62+
def __init__(self, pixel_object, speed, color, peers=None, paused=False, name=None):
63+
self.pixel_object = pixel_object
64+
self.pixel_object.auto_write = False
65+
self.peers = peers if peers else []
66+
"""A sequence of animations to trigger .draw() on when this animation draws."""
67+
self._speed_ns = 0
68+
self._color = None
69+
self._paused = paused
70+
self._next_update = monotonic_ns()
71+
self._time_left_at_pause = 0
72+
self._also_notify = []
73+
self.speed = speed # sets _speed_ns
74+
self.color = color # Triggers _recompute_color
75+
self.name = name
76+
self.notify_cycles = 1
77+
"""Number of cycles to trigger additional cycle_done notifications after"""
78+
self.draw_count = 0
79+
"""Number of animation frames drawn."""
80+
self.cycle_count = 0
81+
"""Number of animation cycles completed."""
82+
83+
def __str__(self):
84+
return "<%s: %s>" % (self.__class__.__name__, self.name)
85+
86+
def animate(self):
87+
"""
88+
Call animate() from your code's main loop. It will draw the animation draw() at intervals
89+
configured by the speed property (set from init).
90+
91+
:return: True if the animation draw cycle was triggered, otherwise False.
92+
"""
93+
if self._paused:
94+
return False
95+
96+
now = monotonic_ns()
97+
if now < self._next_update:
98+
return False
99+
100+
self.draw()
101+
self.draw_count += 1
102+
103+
# Draw related animations together
104+
if self.peers:
105+
for peer in self.peers:
106+
peer.draw()
107+
108+
self._next_update = now + self._speed_ns
109+
return True
110+
111+
def draw(self):
112+
"""
113+
Animation subclasses must implement draw() to render the animation sequence.
114+
Draw must call show().
115+
"""
116+
raise NotImplementedError()
117+
118+
def show(self):
119+
"""
120+
Displays the updated pixels. Called during animates with changes.
121+
"""
122+
self.pixel_object.show()
123+
124+
def freeze(self):
125+
"""
126+
Stops the animation until resumed.
127+
"""
128+
self._paused = True
129+
self._time_left_at_pause = max(0, monotonic_ns() - self._next_update)
130+
131+
def resume(self):
132+
"""
133+
Resumes the animation.
134+
"""
135+
self._next_update = monotonic_ns() + self._time_left_at_pause
136+
self._time_left_at_pause = 0
137+
self._paused = False
138+
139+
def fill(self, color):
140+
"""
141+
Fills the pixel object with a color.
142+
"""
143+
self.pixel_object.fill(color)
144+
145+
@property
146+
def color(self):
147+
"""
148+
The current color.
149+
"""
150+
return self._color
151+
152+
@color.setter
153+
def color(self, color):
154+
if self._color == color:
155+
return
156+
if isinstance(color, int):
157+
color = (color >> 16 & 0xFF, color >> 8 & 0xFF, color & 0xFF)
158+
self._color = color
159+
self._recompute_color(color)
160+
161+
@property
162+
def speed(self):
163+
"""
164+
The animation speed in fractional seconds.
165+
"""
166+
return self._speed_ns / NANOS_PER_SECOND
167+
168+
@speed.setter
169+
def speed(self, seconds):
170+
self._speed_ns = int(seconds * NANOS_PER_SECOND)
171+
172+
def _recompute_color(self, color):
173+
"""
174+
Called if the color is changed, which includes at initialization.
175+
Override as needed.
176+
"""
177+
178+
def cycle_complete(self):
179+
"""
180+
Called by some animations when they complete an animation cycle.
181+
Animations that support cycle complete notifications will have X property set to False.
182+
Override as needed.
183+
"""
184+
self.cycle_count += 1
185+
if self.cycle_count % self.notify_cycles == 0:
186+
for callback in self._also_notify:
187+
callback(self)
188+
189+
def add_cycle_complete_receiver(self, callback):
190+
"""
191+
Adds an additional callback when the cycle completes.
192+
193+
:param callback: Additional callback to trigger when a cycle completes. The callback
194+
is passed the animation object instance.
195+
"""
196+
self._also_notify.append(callback)
197+
198+
def reset(self):
199+
"""
200+
Resets the animation sequence.
201+
"""
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# The MIT License (MIT)
2+
#
3+
# Copyright (c) 2019-2020 Roy Hooper
4+
# Copyright (c) 2020 Kattni Rembor for Adafruit Industries
5+
#
6+
# Permission is hereby granted, free of charge, to any person obtaining a copy
7+
# of this software and associated documentation files (the "Software"), to deal
8+
# in the Software without restriction, including without limitation the rights
9+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
# copies of the Software, and to permit persons to whom the Software is
11+
# furnished to do so, subject to the following conditions:
12+
#
13+
# The above copyright notice and this permission notice shall be included in
14+
# all copies or substantial portions of the Software.
15+
#
16+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
# THE SOFTWARE.
23+
"""
24+
`adafruit_led_animation.animation.blink`
25+
================================================================================
26+
27+
TODO
28+
29+
* Author(s): Roy Hooper, Kattni Rembor
30+
31+
"""
32+
33+
from adafruit_led_animation.animation.colorcycle import ColorCycle
34+
from adafruit_led_animation.color import BLACK
35+
36+
37+
class Blink(ColorCycle):
38+
"""
39+
Blink a color on and off.
40+
41+
:param pixel_object: The initialised LED object.
42+
:param float speed: Animation speed in seconds, e.g. ``0.1``.
43+
:param color: Animation color in ``(r, g, b)`` tuple, or ``0x000000`` hex format.
44+
"""
45+
46+
def __init__(self, pixel_object, speed, color, name=None):
47+
super().__init__(pixel_object, speed, [color, BLACK], name=name)
48+
49+
def _recompute_color(self, color):
50+
self.colors = [color, BLACK]
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# The MIT License (MIT)
2+
#
3+
# Copyright (c) 2019-2020 Roy Hooper
4+
# Copyright (c) 2020 Kattni Rembor for Adafruit Industries
5+
#
6+
# Permission is hereby granted, free of charge, to any person obtaining a copy
7+
# of this software and associated documentation files (the "Software"), to deal
8+
# in the Software without restriction, including without limitation the rights
9+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
# copies of the Software, and to permit persons to whom the Software is
11+
# furnished to do so, subject to the following conditions:
12+
#
13+
# The above copyright notice and this permission notice shall be included in
14+
# all copies or substantial portions of the Software.
15+
#
16+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
# THE SOFTWARE.
23+
"""
24+
`adafruit_led_animation.animation.chase`
25+
================================================================================
26+
27+
TODO
28+
29+
* Author(s): Roy Hooper, Kattni Rembor
30+
31+
"""
32+
33+
from math import ceil
34+
35+
from adafruit_led_animation.animation import Animation
36+
37+
38+
class Chase(Animation):
39+
"""
40+
Chase pixels in one direction in a single color, like a theater marquee sign.
41+
42+
:param pixel_object: The initialised LED object.
43+
:param float speed: Animation speed rate in seconds, e.g. ``0.1``.
44+
:param color: Animation color in ``(r, g, b)`` tuple, or ``0x000000`` hex format.
45+
:param size: Number of pixels to turn on in a row.
46+
:param spacing: Number of pixels to turn off in a row.
47+
:param reverse: Reverse direction of movement.
48+
"""
49+
50+
# pylint: disable=too-many-arguments
51+
def __init__(
52+
self, pixel_object, speed, color, size=2, spacing=3, reverse=False, name=None
53+
):
54+
self._size = size
55+
self._spacing = spacing
56+
self._repeat_width = size + spacing
57+
self._num_repeats = ceil(len(pixel_object) / self._repeat_width)
58+
self._overflow = len(pixel_object) % self._repeat_width
59+
self._direction = 1 if not reverse else -1
60+
self._reverse = reverse
61+
self._offset = 0
62+
63+
def _resetter():
64+
self._offset = 0
65+
self._reverse = reverse
66+
self._direction = 1 if not reverse else -1
67+
68+
self._reset = _resetter
69+
70+
super().__init__(pixel_object, speed, color, name=name)
71+
72+
cycle_complete_supported = True
73+
74+
@property
75+
def reverse(self):
76+
"""
77+
Whether the animation is reversed
78+
"""
79+
return self._reverse
80+
81+
@reverse.setter
82+
def reverse(self, value):
83+
self._reverse = value
84+
self._direction = -1 if self._reverse else 1
85+
86+
def draw(self):
87+
def bar_colors():
88+
bar_no = 0
89+
for i in range(self._offset, 0, -1):
90+
if i > self._spacing:
91+
yield self.bar_color(bar_no, i)
92+
else:
93+
yield self.space_color(bar_no, i)
94+
bar_no = 1
95+
while True:
96+
for bar_pixel in range(self._size):
97+
yield self.bar_color(bar_no, bar_pixel)
98+
for space_pixel in range(self._spacing):
99+
yield self.space_color(bar_no, space_pixel)
100+
bar_no += 1
101+
102+
colorgen = bar_colors()
103+
self.pixel_object[:] = [next(colorgen) for _ in self.pixel_object]
104+
self.show()
105+
106+
if self.draw_count % len(self.pixel_object) == 0:
107+
self.cycle_complete()
108+
self._offset = (self._offset + self._direction) % self._repeat_width
109+
110+
def bar_color(self, n, pixel_no=0): # pylint: disable=unused-argument
111+
"""
112+
Generate the color for the n'th bar_color in the Chase
113+
114+
:param n: The pixel group to get the color for
115+
:param pixel_no: Which pixel in the group to get the color for
116+
"""
117+
return self.color
118+
119+
def space_color(self, n, pixel_no=0): # pylint: disable=unused-argument,no-self-use
120+
"""
121+
Generate the spacing color for the n'th bar_color in the Chase
122+
123+
:param n: The pixel group to get the spacing color for
124+
:param pixel_no: Which pixel in the group to get the spacing color for
125+
"""
126+
return 0
127+
128+
def reset(self):
129+
"""
130+
Reset the animation.
131+
"""
132+
self._reset()

0 commit comments

Comments
 (0)