22#
33# Copyright (c) 2016 Damien P. George
44# Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
5- # Copyright (c) 2019 Carter Nelson
6- # Copyright (c) 2019 Roy Hooper
75#
86# Permission is hereby granted, free of charge, to any person obtaining a copy
97# of this software and associated documentation files (the "Software"), to deal
2725`neopixel` - NeoPixel strip driver
2826====================================================
2927
30- * Author(s): Damien P. George, Scott Shawcroft, Carter Nelson, Roy Hooper
28+ * Author(s): Damien P. George & Scott Shawcroft
3129"""
3230
31+ import math
32+
3333import digitalio
3434from neopixel_write import neopixel_write
35- try :
36- import _pixelbuf
37- except ImportError :
38- import adafruit_pypixelbuf as _pixelbuf
39-
4035
4136__version__ = "0.0.0-auto.0"
4237__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_NeoPixel.git"
4338
44-
4539# Pixel color order constants
46- RGB = 'RGB'
40+ RGB = ( 0 , 1 , 2 )
4741"""Red Green Blue"""
48- GRB = 'GRB'
42+ GRB = ( 1 , 0 , 2 )
4943"""Green Red Blue"""
50- RGBW = 'RGBW'
44+ RGBW = ( 0 , 1 , 2 , 3 )
5145"""Red Green Blue White"""
52- GRBW = 'GRBW'
46+ GRBW = ( 1 , 0 , 2 , 3 )
5347"""Green Red Blue White"""
5448
55-
56- class NeoPixel (_pixelbuf .PixelBuf ):
49+ class NeoPixel :
5750 """
5851 A sequence of neopixels.
5952
@@ -64,7 +57,7 @@ class NeoPixel(_pixelbuf.PixelBuf):
6457 brightness
6558 :param bool auto_write: True if the neopixels should immediately change when set. If False,
6659 `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.
6861
6962 Example for Circuit Playground Express:
7063
@@ -94,37 +87,28 @@ class NeoPixel(_pixelbuf.PixelBuf):
9487 pixels[::2] = [RED] * (len(pixels) // 2)
9588 time.sleep(2)
9689 """
97- bpp = None
98- n = 0
99-
10090 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-
12191 self .pin = digitalio .DigitalInOut (pin )
12292 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
123106
124107 def deinit (self ):
125108 """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 )
128112 self .pin .deinit ()
129113
130114 def __enter__ (self ):
@@ -136,6 +120,100 @@ def __exit__(self, exception_type, exception_value, traceback):
136120 def __repr__ (self ):
137121 return "[" + ", " .join ([str (x ) for x in self ]) + "]"
138122
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+
139217 def write (self ):
140218 """.. deprecated: 1.0.0
141219
@@ -148,8 +226,7 @@ def show(self):
148226
149227 The colors may or may not be showing after this function returns because
150228 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