45
45
import math
46
46
47
47
from . import NANOS_PER_SECOND , monotonic_ns
48
+ from .color import calculate_intensity
48
49
49
50
50
51
class PixelMap :
@@ -69,7 +70,7 @@ class PixelMap:
69
70
pixel_wing_horizontal[0] = (255, 255, 0)
70
71
pixel_wing_horizontal.show()
71
72
72
- To use with individual pixels:
73
+ To use with groups of individual pixels:
73
74
74
75
.. code-block:: python
75
76
@@ -92,24 +93,59 @@ class PixelMap:
92
93
pixel_wing_vertical[0] = (255, 255, 0)
93
94
pixel_wing_vertical.show()
94
95
96
+ To use with individual pixels:
97
+
98
+ .. code-block:: python
99
+
100
+ import board
101
+ import neopixel
102
+ import time
103
+ from adafruit_led_animation.helper import PixelMap
104
+
105
+ pixels = neopixel.NeoPixel(board.D6, 8, auto_write=False)
106
+
107
+ pixel_map = PixelMap(pixels, [
108
+ 0, 7, 1, 6, 2, 5, 3, 4
109
+ ], individual_pixels=True)
110
+
111
+ n = 0
112
+ while True:
113
+ pixel_map[n] = AMBER
114
+ pixel_map.show()
115
+ n = n + 1
116
+ if n > 7:
117
+ n = 0
118
+ pixel_map.fill(0)
119
+ time.sleep(0.25)
120
+
121
+
95
122
"""
96
123
97
124
def __init__ (self , strip , pixel_ranges , individual_pixels = False ):
98
125
self ._pixels = strip
99
126
self ._ranges = pixel_ranges
127
+
100
128
self .n = len (self ._ranges )
129
+ if self .n == 0 :
130
+ raise (ValueError ("A PixelMap must have at least one pixel defined" ))
101
131
self ._individual_pixels = individual_pixels
132
+ self ._expand_ranges ()
133
+
134
+ def _expand_ranges (self ):
135
+ if not self ._individual_pixels :
136
+ self ._ranges = [
137
+ [n for n in range (start , end )] for start , end in self ._ranges
138
+ ]
139
+ return
140
+ if isinstance (self ._ranges [0 ], int ):
141
+ self ._ranges = [[n ] for n in self ._ranges ]
102
142
103
143
def __repr__ (self ):
104
- return "[" + ", " .join ([str (x ) for x in self ]) + "]"
144
+ return "[" + ", " .join ([str (self [ x ] ) for x in range ( self . n ) ]) + "]"
105
145
106
146
def _set_pixels (self , index , val ):
107
- if self ._individual_pixels :
108
- for pixel in self ._ranges [index ]:
109
- self ._pixels [pixel ] = val
110
- else :
111
- range_start , range_stop = self ._ranges [index ]
112
- self ._pixels [range_start :range_stop ] = [val ] * (range_stop - range_start )
147
+ for pixel in self ._ranges [index ]:
148
+ self ._pixels [pixel ] = val
113
149
114
150
def __setitem__ (self , index , val ):
115
151
if isinstance (index , slice ):
@@ -124,7 +160,7 @@ def __setitem__(self, index, val):
124
160
else :
125
161
self ._set_pixels (index , val )
126
162
127
- if not self ._pixels .auto_write :
163
+ if self ._pixels .auto_write :
128
164
self .show ()
129
165
130
166
def __getitem__ (self , index ):
@@ -160,13 +196,9 @@ def fill(self, color):
160
196
161
197
:param color: Color to fill all pixels referenced by this PixelMap definition with.
162
198
"""
163
- if self ._individual_pixels :
164
- for pixels in self ._ranges :
165
- for pixel in pixels :
166
- self ._pixels [pixel ] = color
167
- else :
168
- for start , stop in self ._ranges :
169
- self ._pixels [start :stop ] = [color ] * (stop - start )
199
+ for pixels in self ._ranges :
200
+ for pixel in pixels :
201
+ self ._pixels [pixel ] = color
170
202
171
203
def show (self ):
172
204
"""
@@ -273,7 +305,7 @@ def mapper(x, y):
273
305
return mapper
274
306
275
307
276
- class PixelSubset :
308
+ class PixelSubset ( PixelMap ) :
277
309
"""
278
310
PixelSubset lets you work with a subset of a pixel object.
279
311
@@ -295,78 +327,18 @@ class PixelSubset:
295
327
"""
296
328
297
329
def __init__ (self , pixel_object , start , end ):
298
- self ._pixels = pixel_object
299
- self ._start = start
300
- self ._end = end
301
- self .n = self ._end - self ._start
302
-
303
- def __repr__ (self ):
304
- return "[" + ", " .join ([str (x ) for x in self ]) + "]"
305
-
306
- def __setitem__ (self , index , val ):
307
- if isinstance (index , slice ):
308
- start , stop , step = index .indices (self .n )
309
- self ._pixels [start + self ._start : stop + self ._start : step ] = val
310
- else :
311
- self ._pixels [index + self ._start ] = val
312
-
313
- if not self ._pixels .auto_write :
314
- self .show ()
315
-
316
- def __getitem__ (self , index ):
317
- if isinstance (index , slice ):
318
- start , stop , step = index .indices (self .n )
319
- return self ._pixels [start + self ._start : stop + self ._start : step ]
320
- if index < 0 :
321
- index += len (self )
322
- if index >= self .n or index < 0 :
323
- raise IndexError
324
- return self ._pixels [index ]
325
-
326
- def __len__ (self ):
327
- return self .n
328
-
329
- @property
330
- def brightness (self ):
331
- """
332
- brightness from the underlying strip.
333
- """
334
- return self ._pixels .brightness
335
-
336
- @brightness .setter
337
- def brightness (self , brightness ):
338
- self ._pixels .brightness = min (max (brightness , 0.0 ), 1.0 )
339
-
340
- def fill (self , color ):
341
- """
342
- Fill the used pixel ranges with color.
343
- """
344
- self ._pixels [self ._start : self ._end ] = [color ] * (self .n )
345
-
346
- def show (self ):
347
- """
348
- Shows the pixels on the underlying strip.
349
- """
350
- self ._pixels .show ()
351
-
352
- @property
353
- def auto_write (self ):
354
- """
355
- auto_write from the underlying strip.
356
- """
357
- return self ._pixels .auto_write
358
-
359
- @auto_write .setter
360
- def auto_write (self , value ):
361
- self ._pixels .auto_write = value
330
+ super ().__init__ (
331
+ pixel_object ,
332
+ pixel_ranges = [[n ] for n in range (start , end )],
333
+ individual_pixels = True ,
334
+ )
362
335
363
336
364
- def pulse_generator (period : float , animation_object , white = False , dotstar_pwm = False ):
337
+ def pulse_generator (period : float , animation_object , dotstar_pwm = False ):
365
338
"""
366
339
Generates a sequence of colors for a pulse, based on the time period specified.
367
340
:param period: Pulse duration in seconds.
368
341
:param animation_object: An animation object to interact with.
369
- :param white: Whether the pixel strip has a white pixel.
370
342
:param dotstar_pwm: Whether to use the dostar per pixel PWM value for brightness control.
371
343
"""
372
344
period = int (period * NANOS_PER_SECOND )
@@ -376,7 +348,6 @@ def pulse_generator(period: float, animation_object, white=False, dotstar_pwm=Fa
376
348
cycle_position = 0
377
349
last_pos = 0
378
350
while True :
379
- fill_color = list (animation_object .color )
380
351
now = monotonic_ns ()
381
352
time_since_last_draw = now - last_update
382
353
last_update = now
@@ -388,12 +359,12 @@ def pulse_generator(period: float, animation_object, white=False, dotstar_pwm=Fa
388
359
pos = period - pos
389
360
intensity = pos / half_period
390
361
if dotstar_pwm :
391
- fill_color = (fill_color [0 ], fill_color [1 ], fill_color [2 ], intensity )
362
+ fill_color = (
363
+ animation_object .color [0 ],
364
+ animation_object .color [1 ],
365
+ animation_object .color [2 ],
366
+ intensity ,
367
+ )
392
368
yield fill_color
393
369
continue
394
- if white and len (fill_color ) == 4 :
395
- fill_color [3 ] = int (fill_color [3 ] * intensity )
396
- fill_color [0 ] = int (fill_color [0 ] * intensity )
397
- fill_color [1 ] = int (fill_color [1 ] * intensity )
398
- fill_color [2 ] = int (fill_color [2 ] * intensity )
399
- yield fill_color
370
+ yield calculate_intensity (animation_object .color , intensity )
0 commit comments