2
2
#
3
3
# Copyright (c) 2016 Damien P. George
4
4
# Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
5
- # Copyright (c) 2019 Carter Nelson
6
- # Copyright (c) 2019 Roy Hooper
7
5
#
8
6
# Permission is hereby granted, free of charge, to any person obtaining a copy
9
7
# of this software and associated documentation files (the "Software"), to deal
27
25
`neopixel` - NeoPixel strip driver
28
26
====================================================
29
27
30
- * Author(s): Damien P. George, Scott Shawcroft, Carter Nelson, Roy Hooper
28
+ * Author(s): Damien P. George & Scott Shawcroft
31
29
"""
32
30
31
+ import math
32
+
33
33
import digitalio
34
34
from neopixel_write import neopixel_write
35
- try :
36
- import _pixelbuf
37
- except ImportError :
38
- import adafruit_pypixelbuf as _pixelbuf
39
-
40
35
41
36
__version__ = "0.0.0-auto.0"
42
37
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_NeoPixel.git"
43
38
44
-
45
39
# Pixel color order constants
46
- RGB = 'RGB'
40
+ RGB = ( 0 , 1 , 2 )
47
41
"""Red Green Blue"""
48
- GRB = 'GRB'
42
+ GRB = ( 1 , 0 , 2 )
49
43
"""Green Red Blue"""
50
- RGBW = 'RGBW'
44
+ RGBW = ( 0 , 1 , 2 , 3 )
51
45
"""Red Green Blue White"""
52
- GRBW = 'GRBW'
46
+ GRBW = ( 1 , 0 , 2 , 3 )
53
47
"""Green Red Blue White"""
54
48
55
-
56
- class NeoPixel (_pixelbuf .PixelBuf ):
49
+ class NeoPixel :
57
50
"""
58
51
A sequence of neopixels.
59
52
@@ -64,7 +57,7 @@ class NeoPixel(_pixelbuf.PixelBuf):
64
57
brightness
65
58
:param bool auto_write: True if the neopixels should immediately change when set. If False,
66
59
`show` must be called explicitly.
67
- :param str : Set the pixel color channel order. GRBW is set by default.
60
+ :param tuple pixel_order : Set the pixel color channel order. GRBW is set by default.
68
61
69
62
Example for Circuit Playground Express:
70
63
@@ -94,37 +87,28 @@ class NeoPixel(_pixelbuf.PixelBuf):
94
87
pixels[::2] = [RED] * (len(pixels) // 2)
95
88
time.sleep(2)
96
89
"""
97
- bpp = None
98
- n = 0
99
-
100
90
def __init__ (self , pin , n , * , bpp = 3 , brightness = 1.0 , auto_write = True , pixel_order = None ):
101
- self .bpp = bpp
102
- self .n = n
103
-
104
- if not pixel_order :
105
- pixel_order = GRB if bpp == 3 else GRBW
106
- else :
107
- self .bpp = bpp = len (pixel_order )
108
- if isinstance (pixel_order , tuple ):
109
- order_chars = RGBW
110
- order = []
111
- for char_no , order in enumerate (pixel_order ):
112
- order [pixel_order ] = order_chars [char_no ]
113
- pixel_order = '' .join (order )
114
-
115
- super ().__init__ (n , bytearray (self .n * bpp ),
116
- brightness = brightness ,
117
- rawbuf = bytearray (self .n * bpp ),
118
- byteorder = pixel_order ,
119
- auto_write = auto_write )
120
-
121
91
self .pin = digitalio .DigitalInOut (pin )
122
92
self .pin .direction = digitalio .Direction .OUTPUT
93
+ self .n = n
94
+ if pixel_order is None :
95
+ self .order = GRBW
96
+ self .bpp = bpp
97
+ else :
98
+ self .order = pixel_order
99
+ self .bpp = len (self .order )
100
+ self .buf = bytearray (self .n * self .bpp )
101
+ # Set auto_write to False temporarily so brightness setter does _not_
102
+ # call show() while in __init__.
103
+ self .auto_write = False
104
+ self .brightness = brightness
105
+ self .auto_write = auto_write
123
106
124
107
def deinit (self ):
125
108
"""Blank out the NeoPixels and release the pin."""
126
- self .fill (0 )
127
- self .show ()
109
+ for i in range (len (self .buf )):
110
+ self .buf [i ] = 0
111
+ neopixel_write (self .pin , self .buf )
128
112
self .pin .deinit ()
129
113
130
114
def __enter__ (self ):
@@ -136,6 +120,100 @@ def __exit__(self, exception_type, exception_value, traceback):
136
120
def __repr__ (self ):
137
121
return "[" + ", " .join ([str (x ) for x in self ]) + "]"
138
122
123
+ def _set_item (self , index , value ):
124
+ if index < 0 :
125
+ index += len (self )
126
+ if index >= self .n or index < 0 :
127
+ raise IndexError
128
+ offset = index * self .bpp
129
+ r = 0
130
+ g = 0
131
+ b = 0
132
+ w = 0
133
+ if isinstance (value , int ):
134
+ if value >> 24 :
135
+ raise ValueError ("only bits 0->23 valid for integer input" )
136
+ r = value >> 16
137
+ g = (value >> 8 ) & 0xff
138
+ b = value & 0xff
139
+ w = 0
140
+ # If all components are the same and we have a white pixel then use it
141
+ # instead of the individual components.
142
+ if self .bpp == 4 and r == g and g == b :
143
+ w = r
144
+ r = 0
145
+ g = 0
146
+ b = 0
147
+ elif (len (value ) == self .bpp ) or ((len (value ) == 3 ) and (self .bpp == 4 )):
148
+ if len (value ) == 3 :
149
+ r , g , b = value
150
+ else :
151
+ r , g , b , w = value
152
+ else :
153
+ raise ValueError ("Color tuple size does not match pixel_order." )
154
+
155
+ self .buf [offset + self .order [0 ]] = r
156
+ self .buf [offset + self .order [1 ]] = g
157
+ self .buf [offset + self .order [2 ]] = b
158
+ if self .bpp == 4 :
159
+ self .buf [offset + self .order [3 ]] = w
160
+
161
+ def __setitem__ (self , index , val ):
162
+ if isinstance (index , slice ):
163
+ start , stop , step = index .indices (len (self .buf ) // self .bpp )
164
+ length = stop - start
165
+ if step != 0 :
166
+ length = math .ceil (length / step )
167
+ if len (val ) != length :
168
+ raise ValueError ("Slice and input sequence size do not match." )
169
+ for val_i , in_i in enumerate (range (start , stop , step )):
170
+ self ._set_item (in_i , val [val_i ])
171
+ else :
172
+ self ._set_item (index , val )
173
+
174
+ if self .auto_write :
175
+ self .show ()
176
+
177
+ def __getitem__ (self , index ):
178
+ if isinstance (index , slice ):
179
+ out = []
180
+ for in_i in range (* index .indices (len (self .buf ) // self .bpp )):
181
+ out .append (tuple (self .buf [in_i * self .bpp + self .order [i ]]
182
+ for i in range (self .bpp )))
183
+ return out
184
+ if index < 0 :
185
+ index += len (self )
186
+ if index >= self .n or index < 0 :
187
+ raise IndexError
188
+ offset = index * self .bpp
189
+ return tuple (self .buf [offset + self .order [i ]]
190
+ for i in range (self .bpp ))
191
+
192
+ def __len__ (self ):
193
+ return len (self .buf ) // self .bpp
194
+
195
+ @property
196
+ def brightness (self ):
197
+ """Overall brightness of the pixel"""
198
+ return self ._brightness
199
+
200
+ @brightness .setter
201
+ def brightness (self , brightness ):
202
+ # pylint: disable=attribute-defined-outside-init
203
+ self ._brightness = min (max (brightness , 0.0 ), 1.0 )
204
+ if self .auto_write :
205
+ self .show ()
206
+
207
+ def fill (self , color ):
208
+ """Colors all pixels the given ***color***."""
209
+ auto_write = self .auto_write
210
+ self .auto_write = False
211
+ for i , _ in enumerate (self ):
212
+ self [i ] = color
213
+ if auto_write :
214
+ self .show ()
215
+ self .auto_write = auto_write
216
+
139
217
def write (self ):
140
218
""".. deprecated: 1.0.0
141
219
@@ -148,8 +226,7 @@ def show(self):
148
226
149
227
The colors may or may not be showing after this function returns because
150
228
it may be done asynchronously."""
151
- neopixel_write (self .pin , self .buf )
152
-
153
- def fill (self , color ):
154
- """Colors all pixels the given ***color***."""
155
- _pixelbuf .fill (self , color )
229
+ if self .brightness > 0.99 :
230
+ neopixel_write (self .pin , self .buf )
231
+ else :
232
+ neopixel_write (self .pin , bytearray ([int (i * self .brightness ) for i in self .buf ]))
0 commit comments