From 8fe9702f1b3344a4215c0ec4227d619d1678b8af Mon Sep 17 00:00:00 2001 From: Roy Hooper Date: Sun, 17 Jun 2018 21:20:11 -0400 Subject: [PATCH 01/19] variant that works with pixelbuf --- neopixel.py | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/neopixel.py b/neopixel.py index 7b7261b..2ade84f 100644 --- a/neopixel.py +++ b/neopixel.py @@ -32,6 +32,11 @@ import digitalio from neopixel_write import neopixel_write +try: + from pixelbuf import PixelBuf +except: + PixelBuf = None + __version__ = "0.0.0-auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_NeoPixel.git" @@ -97,12 +102,20 @@ def __init__(self, pin, n, *, bpp=3, brightness=1.0, auto_write=True, pixel_orde else: self.order = pixel_order self.bpp = len(self.order) - self.buf = bytearray(self.n * self.bpp) # Set auto_write to False temporarily so brightness setter does _not_ # call show() while in __init__. self.auto_write = False - self.brightness = brightness self.auto_write = auto_write + if PixelBuf: + print("PB INIT") + self.buf = PixelBuf(self.n, bytearray(self.n * self.bpp), + bpp=self.bpp, brightness=brightness, + rawbuf=bytearray(self.n * self.bpp)) + NeoPixel.__setitem__ = NeoPixel.__setitem_pb__ + NeoPixel.__getitem__ = NeoPixel.__getitem_pb__ + else: + self.buf = bytearray(self.n * self.bpp) + self.brightness = brightness def deinit(self): """Blank out the NeoPixels and release the pin.""" @@ -169,6 +182,15 @@ def __setitem__(self, index, val): if self.auto_write: self.show() + def __setitem_pb__(self, index, val): + if isinstance(index, slice): + self.buf[index.start:index.stop:index.step] = val + else: + self.buf[index] = val + + if self.auto_write: + self.show() + def __getitem__(self, index): if isinstance(index, slice): out = [] @@ -184,18 +206,29 @@ def __getitem__(self, index): return tuple(self.buf[offset + self.order[i]] for i in range(self.bpp)) + def __getitem_pb__(self, index): + if isinstance(index, slice): + return self.buf[index.start:index.stop:index.step] + else: + return self.buf[index] + def __len__(self): return len(self.buf) // self.bpp @property def brightness(self): """Overall brightness of the pixel""" + if PixelBuf: + return self.buf.brightness return self._brightness @brightness.setter def brightness(self, brightness): # pylint: disable=attribute-defined-outside-init - self._brightness = min(max(brightness, 0.0), 1.0) + if PixelBuf: + self.buf.brightness = brightness + else: + self._brightness = min(max(brightness, 0.0), 1.0) if self.auto_write: self.show() @@ -221,7 +254,9 @@ def show(self): The colors may or may not be showing after this function returns because it may be done asynchronously.""" - if self.brightness > 0.99: + if PixelBuf: + neopixel_write(self.pin, self.buf.buf) + elif self.brightness > 0.99: neopixel_write(self.pin, self.buf) else: neopixel_write(self.pin, bytearray([int(i * self.brightness) for i in self.buf])) From 83d4f0a701f9198f1b40663724135be1bc8bb8ab Mon Sep 17 00:00:00 2001 From: Roy Hooper Date: Sun, 17 Jun 2018 21:47:08 -0400 Subject: [PATCH 02/19] fix deinit --- neopixel.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/neopixel.py b/neopixel.py index 2ade84f..f56da9c 100644 --- a/neopixel.py +++ b/neopixel.py @@ -107,7 +107,6 @@ def __init__(self, pin, n, *, bpp=3, brightness=1.0, auto_write=True, pixel_orde self.auto_write = False self.auto_write = auto_write if PixelBuf: - print("PB INIT") self.buf = PixelBuf(self.n, bytearray(self.n * self.bpp), bpp=self.bpp, brightness=brightness, rawbuf=bytearray(self.n * self.bpp)) @@ -121,7 +120,10 @@ def deinit(self): """Blank out the NeoPixels and release the pin.""" for i in range(len(self.buf)): self.buf[i] = 0 - neopixel_write(self.pin, self.buf) + if PixelBuf: + neopixel_write(self.pin, self.buf.buf) + else: + neopixel_write(self.pin, self.buf) self.pin.deinit() def __enter__(self): From 63a5340d30b47475d919098b295415cab87a43b5 Mon Sep 17 00:00:00 2001 From: Roy Hooper Date: Mon, 18 Jun 2018 22:31:17 -0400 Subject: [PATCH 03/19] strip all non-pixelbuf code --- neopixel.py | 121 ++++++---------------------------------------------- 1 file changed, 14 insertions(+), 107 deletions(-) diff --git a/neopixel.py b/neopixel.py index f56da9c..ec5942d 100644 --- a/neopixel.py +++ b/neopixel.py @@ -32,23 +32,20 @@ import digitalio from neopixel_write import neopixel_write -try: - from pixelbuf import PixelBuf -except: - PixelBuf = None +from pixelbuf import PixelBuf __version__ = "0.0.0-auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_NeoPixel.git" # Pixel color order constants -RGB = (0, 1, 2) +RGB = PixelBuf.RGB """Red Green Blue""" -GRB = (1, 0, 2) +GRB = PixelBuf.GRB """Green Red Blue""" -RGBW = (0, 1, 2, 3) +RGBW = PixelBuf.RGB """Red Green Blue White""" -GRBW = (1, 0, 2, 3) +GRBW = PixelBuf.GRB """Green Red Blue White""" class NeoPixel: @@ -96,34 +93,18 @@ def __init__(self, pin, n, *, bpp=3, brightness=1.0, auto_write=True, pixel_orde self.pin = digitalio.DigitalInOut(pin) self.pin.direction = digitalio.Direction.OUTPUT self.n = n - if pixel_order is None: - self.order = GRBW - self.bpp = bpp - else: - self.order = pixel_order - self.bpp = len(self.order) - # Set auto_write to False temporarily so brightness setter does _not_ - # call show() while in __init__. - self.auto_write = False self.auto_write = auto_write - if PixelBuf: - self.buf = PixelBuf(self.n, bytearray(self.n * self.bpp), - bpp=self.bpp, brightness=brightness, - rawbuf=bytearray(self.n * self.bpp)) - NeoPixel.__setitem__ = NeoPixel.__setitem_pb__ - NeoPixel.__getitem__ = NeoPixel.__getitem_pb__ - else: - self.buf = bytearray(self.n * self.bpp) - self.brightness = brightness + self.bpp = bpp + self.buf = PixelBuf(self.n, bytearray(self.n * bpp), + bpp=self.bpp, brightness=brightness, + rawbuf=bytearray(self.n * bpp), + byteorder=pixel_order or PixelBuf.BGR) def deinit(self): """Blank out the NeoPixels and release the pin.""" for i in range(len(self.buf)): self.buf[i] = 0 - if PixelBuf: - neopixel_write(self.pin, self.buf.buf) - else: - neopixel_write(self.pin, self.buf) + neopixel_write(self.pin, self.buf.buf) self.pin.deinit() def __enter__(self): @@ -135,56 +116,7 @@ def __exit__(self, exception_type, exception_value, traceback): def __repr__(self): return "[" + ", ".join([str(x) for x in self]) + "]" - def _set_item(self, index, value): - if index < 0: - index += len(self) - if index >= self.n or index < 0: - raise IndexError - offset = index * self.bpp - r = 0 - g = 0 - b = 0 - w = 0 - if isinstance(value, int): - r = value >> 16 - g = (value >> 8) & 0xff - b = value & 0xff - w = 0 - # If all components are the same and we have a white pixel then use it - # instead of the individual components. - if self.bpp == 4 and r == g and g == b: - w = r - r = 0 - g = 0 - b = 0 - elif len(value) == self.bpp: - if self.bpp == 3: - r, g, b = value - else: - r, g, b, w = value - self.buf[offset + self.order[0]] = r - self.buf[offset + self.order[1]] = g - self.buf[offset + self.order[2]] = b - if self.bpp == 4: - self.buf[offset + self.order[3]] = w - def __setitem__(self, index, val): - if isinstance(index, slice): - start, stop, step = index.indices(len(self.buf) // self.bpp) - length = stop - start - if step != 0: - length = math.ceil(length / step) - if len(val) != length: - raise ValueError("Slice and input sequence size do not match.") - for val_i, in_i in enumerate(range(start, stop, step)): - self._set_item(in_i, val[val_i]) - else: - self._set_item(index, val) - - if self.auto_write: - self.show() - - def __setitem_pb__(self, index, val): if isinstance(index, slice): self.buf[index.start:index.stop:index.step] = val else: @@ -194,21 +126,6 @@ def __setitem_pb__(self, index, val): self.show() def __getitem__(self, index): - if isinstance(index, slice): - out = [] - for in_i in range(*index.indices(len(self.buf) // self.bpp)): - out.append(tuple(self.buf[in_i * self.bpp + self.order[i]] - for i in range(self.bpp))) - return out - if index < 0: - index += len(self) - if index >= self.n or index < 0: - raise IndexError - offset = index * self.bpp - return tuple(self.buf[offset + self.order[i]] - for i in range(self.bpp)) - - def __getitem_pb__(self, index): if isinstance(index, slice): return self.buf[index.start:index.stop:index.step] else: @@ -220,17 +137,12 @@ def __len__(self): @property def brightness(self): """Overall brightness of the pixel""" - if PixelBuf: - return self.buf.brightness - return self._brightness + return self.buf.brightness @brightness.setter def brightness(self, brightness): # pylint: disable=attribute-defined-outside-init - if PixelBuf: - self.buf.brightness = brightness - else: - self._brightness = min(max(brightness, 0.0), 1.0) + self.buf.brightness = brightness if self.auto_write: self.show() @@ -256,9 +168,4 @@ def show(self): The colors may or may not be showing after this function returns because it may be done asynchronously.""" - if PixelBuf: - neopixel_write(self.pin, self.buf.buf) - elif self.brightness > 0.99: - neopixel_write(self.pin, self.buf) - else: - neopixel_write(self.pin, bytearray([int(i * self.brightness) for i in self.buf])) + neopixel_write(self.pin, self.buf.buf) From 4d126731c71501903b1a5be148b6354a6d6774c2 Mon Sep 17 00:00:00 2001 From: Roy Hooper Date: Sat, 30 Jun 2018 23:57:38 -0400 Subject: [PATCH 04/19] prepare for pixelbuf changes --- neopixel.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/neopixel.py b/neopixel.py index ec5942d..f1d3b46 100644 --- a/neopixel.py +++ b/neopixel.py @@ -32,21 +32,12 @@ import digitalio from neopixel_write import neopixel_write -from pixelbuf import PixelBuf +from pixelbuf import PixelBuf, RGB, GRB, RGBW, GRBW __version__ = "0.0.0-auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_NeoPixel.git" -# Pixel color order constants -RGB = PixelBuf.RGB -"""Red Green Blue""" -GRB = PixelBuf.GRB -"""Green Red Blue""" -RGBW = PixelBuf.RGB -"""Red Green Blue White""" -GRBW = PixelBuf.GRB -"""Green Red Blue White""" class NeoPixel: """ @@ -95,10 +86,11 @@ def __init__(self, pin, n, *, bpp=3, brightness=1.0, auto_write=True, pixel_orde self.n = n self.auto_write = auto_write self.bpp = bpp + # TODO switch to correct byteorder if bpp specified but not pixel_order self.buf = PixelBuf(self.n, bytearray(self.n * bpp), bpp=self.bpp, brightness=brightness, rawbuf=bytearray(self.n * bpp), - byteorder=pixel_order or PixelBuf.BGR) + byteorder=pixel_order or GRB) def deinit(self): """Blank out the NeoPixels and release the pin.""" From 5f9664461e3ca92c27f7c93f8572923ccb9786ba Mon Sep 17 00:00:00 2001 From: Roy Hooper Date: Sat, 23 Nov 2019 16:03:57 -0500 Subject: [PATCH 05/19] continued work on making NeoPixel a subclass of _pixelbuf.PixelBuf --- neopixel.py | 85 ++++++++++++++++++++++++++--------------------------- 1 file changed, 41 insertions(+), 44 deletions(-) diff --git a/neopixel.py b/neopixel.py index f1d3b46..25e2b93 100644 --- a/neopixel.py +++ b/neopixel.py @@ -32,14 +32,31 @@ import digitalio from neopixel_write import neopixel_write -from pixelbuf import PixelBuf, RGB, GRB, RGBW, GRBW +try: + import _pixelbuf +except ImportError: + import pypixelbuf as _pixelbuf __version__ = "0.0.0-auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_NeoPixel.git" -class NeoPixel: +# Pixel color order constants +RGB = 'rgb' +"""Red Green Blue""" +GRB = 'grb' +"""Green Red Blue""" +RGBW = 'rgbw' +"""Red Green Blue White""" +GRBW = 'grbw' +"""Green Red Blue White""" + + +class NeoPixel(_pixelbuf.PixelBuf): + + bpp = None + n = 0 """ A sequence of neopixels. @@ -50,7 +67,7 @@ class NeoPixel: brightness :param bool auto_write: True if the neopixels should immediately change when set. If False, `show` must be called explicitly. - :param tuple pixel_order: Set the pixel color channel order. GRBW is set by default. + :param str: Set the pixel color channel order. GRBW is set by default. Example for Circuit Playground Express: @@ -83,20 +100,30 @@ class NeoPixel: def __init__(self, pin, n, *, bpp=3, brightness=1.0, auto_write=True, pixel_order=None): self.pin = digitalio.DigitalInOut(pin) self.pin.direction = digitalio.Direction.OUTPUT - self.n = n - self.auto_write = auto_write self.bpp = bpp - # TODO switch to correct byteorder if bpp specified but not pixel_order - self.buf = PixelBuf(self.n, bytearray(self.n * bpp), - bpp=self.bpp, brightness=brightness, - rawbuf=bytearray(self.n * bpp), - byteorder=pixel_order or GRB) + self.n = n + if not pixel_order: + pixel_order = 'grb' if bpp == 3 else 'grbw' + else: + self.bpp = bpp = len(pixel_order) + # Backwards compatibility with tuples + if isinstance(pixel_order, tuple): + order_chars = 'rgbw' + order = [] + for char_no, order in enumerate(pixel_order): + order[pixel_order] = order_chars[char_no] + pixel_order = ''.join(order) + + super().__init__(n, bytearray(self.n * bpp), + brightness=brightness, + rawbuf=bytearray(self.n * bpp), + byteorder=pixel_order, + auto_write=auto_write) def deinit(self): """Blank out the NeoPixels and release the pin.""" - for i in range(len(self.buf)): - self.buf[i] = 0 - neopixel_write(self.pin, self.buf.buf) + self.fill(0) + self.show() self.pin.deinit() def __enter__(self): @@ -108,36 +135,6 @@ def __exit__(self, exception_type, exception_value, traceback): def __repr__(self): return "[" + ", ".join([str(x) for x in self]) + "]" - def __setitem__(self, index, val): - if isinstance(index, slice): - self.buf[index.start:index.stop:index.step] = val - else: - self.buf[index] = val - - if self.auto_write: - self.show() - - def __getitem__(self, index): - if isinstance(index, slice): - return self.buf[index.start:index.stop:index.step] - else: - return self.buf[index] - - def __len__(self): - return len(self.buf) // self.bpp - - @property - def brightness(self): - """Overall brightness of the pixel""" - return self.buf.brightness - - @brightness.setter - def brightness(self, brightness): - # pylint: disable=attribute-defined-outside-init - self.buf.brightness = brightness - if self.auto_write: - self.show() - def fill(self, color): """Colors all pixels the given ***color***.""" auto_write = self.auto_write @@ -160,4 +157,4 @@ def show(self): The colors may or may not be showing after this function returns because it may be done asynchronously.""" - neopixel_write(self.pin, self.buf.buf) + neopixel_write(self.pin, self.buf) From b0cb16e4f1f1df8cf87112ae213780bd8a46648b Mon Sep 17 00:00:00 2001 From: Roy Hooper Date: Fri, 29 Nov 2019 19:18:28 -0500 Subject: [PATCH 06/19] remove fill, move pin init after pixelbuf init --- neopixel.py | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/neopixel.py b/neopixel.py index c6ed0e9..e25b1f2 100644 --- a/neopixel.py +++ b/neopixel.py @@ -48,13 +48,13 @@ # Pixel color order constants -RGB = 'rgb' +RGB = 'RGB' """Red Green Blue""" -GRB = 'grb' +GRB = 'GRB' """Green Red Blue""" -RGBW = 'rgbw' +RGBW = 'RGBW' """Red Green Blue White""" -GRBW = 'grbw' +GRBW = 'GRBW' """Green Red Blue White""" @@ -103,17 +103,14 @@ class NeoPixel(_pixelbuf.PixelBuf): time.sleep(2) """ def __init__(self, pin, n, *, bpp=3, brightness=1.0, auto_write=True, pixel_order=None): - self.pin = digitalio.DigitalInOut(pin) - self.pin.direction = digitalio.Direction.OUTPUT self.bpp = bpp self.n = n if not pixel_order: - pixel_order = 'grb' if bpp == 3 else 'grbw' + pixel_order = GRB if bpp == 3 else GRBW else: self.bpp = bpp = len(pixel_order) - # Backwards compatibility with tuples if isinstance(pixel_order, tuple): - order_chars = 'rgbw' + order_chars = RGBW order = [] for char_no, order in enumerate(pixel_order): order[pixel_order] = order_chars[char_no] @@ -125,6 +122,9 @@ def __init__(self, pin, n, *, bpp=3, brightness=1.0, auto_write=True, pixel_orde byteorder=pixel_order, auto_write=auto_write) + self.pin = digitalio.DigitalInOut(pin) + self.pin.direction = digitalio.Direction.OUTPUT + def deinit(self): """Blank out the NeoPixels and release the pin.""" self.fill(0) @@ -140,16 +140,6 @@ def __exit__(self, exception_type, exception_value, traceback): def __repr__(self): return "[" + ", ".join([str(x) for x in self]) + "]" - def fill(self, color): - """Colors all pixels the given ***color***.""" - auto_write = self.auto_write - self.auto_write = False - for i, _ in enumerate(self): - self[i] = color - if auto_write: - self.show() - self.auto_write = auto_write - def write(self): """.. deprecated: 1.0.0 From dd60236d57757ac738fd37fcdf791d8a1688f5ed Mon Sep 17 00:00:00 2001 From: Roy Hooper Date: Fri, 29 Nov 2019 19:28:49 -0500 Subject: [PATCH 07/19] Add NeoPixel_SPI from master --- neopixel.py | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/neopixel.py b/neopixel.py index e25b1f2..46d9360 100644 --- a/neopixel.py +++ b/neopixel.py @@ -103,6 +103,11 @@ class NeoPixel(_pixelbuf.PixelBuf): time.sleep(2) """ def __init__(self, pin, n, *, bpp=3, brightness=1.0, auto_write=True, pixel_order=None): + self._configure(n, bpp, brightness, auto_write, pixel_order) + self.pin = digitalio.DigitalInOut(pin) + self.pin.direction = digitalio.Direction.OUTPUT + + def _configure(self, n, bpp=3, brightness=1.0, auto_write=True, pixel_order=None): self.bpp = bpp self.n = n if not pixel_order: @@ -122,9 +127,6 @@ def __init__(self, pin, n, *, bpp=3, brightness=1.0, auto_write=True, pixel_orde byteorder=pixel_order, auto_write=auto_write) - self.pin = digitalio.DigitalInOut(pin) - self.pin.direction = digitalio.Direction.OUTPUT - def deinit(self): """Blank out the NeoPixels and release the pin.""" self.fill(0) @@ -153,3 +155,69 @@ def show(self): The colors may or may not be showing after this function returns because it may be done asynchronously.""" neopixel_write(self.pin, self.buf) + + +class NeoPixel_SPI(NeoPixel): + """ + A sequence of neopixels. + + :param ~busio.SPI spi: The SPI bus to output neopixel data on. + :param int n: The number of neopixels in the chain + :param int bpp: Bytes per pixel. 3 for RGB and 4 for RGBW pixels. + :param float brightness: Brightness of the pixels between 0.0 and 1.0 where 1.0 is full + brightness + :param bool auto_write: True if the neopixels should immediately change when set. If False, + `show` must be called explicitly. + :param tuple pixel_order: Set the pixel color channel order. GRBW is set by default. + + Example: + + .. code-block:: python + + import board + import neopixel + + pixels = neopixel.NeoPixel_SPI(board.SPI(), 10) + pixels.fill(0xff0000) + """ + #pylint: disable=invalid-name, super-init-not-called + + FREQ = 6400000 # 800kHz * 8, actual may be different + TRST = 80e-6 # Reset code low level time + + def __init__(self, spi, n, *, bpp=3, brightness=1.0, auto_write=True, pixel_order=None): + self._configure(n, bpp, brightness, auto_write, pixel_order) + + from adafruit_bus_device.spi_device import SPIDevice + self._spi = SPIDevice(spi, baudrate=self.FREQ) + with self._spi as spibus: + try: + # get actual SPI frequency + freq = spibus.frequency + except AttributeError: + # use nominal + freq = self.FREQ + self.RESET = bytes([0]*round(freq*self.TRST)) + self.spibuf = bytearray(8*len(self.buf)) + + def show(self): + """Shows the new colors on the pixels themselves if they haven't already + been autowritten.""" + self._transmogrify() + with self._spi as spi: + # write out special byte sequence surrounded by RESET + # leading RESET needed for cases where MOSI rests HI + spi.write(self.RESET + self.spibuf + self.RESET) + + def _transmogrify(self): + """Turn every BIT of buf into a special BYTE pattern.""" + k = 0 + for byte in self.buf: + byte = int(byte * self.brightness) + # MSB first + for i in range(7, -1, -1): + if byte >> i & 0x01: + self.spibuf[k] = 0b11110000 # A NeoPixel 1 bit + else: + self.spibuf[k] = 0b11000000 # A NeoPixel 0 bit + k += 1 From 97e36fa6fdd66a0781146531748e1bb16a6fc539 Mon Sep 17 00:00:00 2001 From: Roy Hooper Date: Sat, 30 Nov 2019 19:30:42 -0500 Subject: [PATCH 08/19] fix lint or at least make pylint happy --- .pylintrc | 3 ++- neopixel.py | 22 ++++++++++------------ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/.pylintrc b/.pylintrc index cb8d23d..039eaec 100644 --- a/.pylintrc +++ b/.pylintrc @@ -119,7 +119,8 @@ spelling-store-unknown-words=no [MISCELLANEOUS] # List of note tags to take in consideration, separated by a comma. -notes=FIXME,XXX,TODO +# notes=FIXME,XXX,TODO +notes=FIXME,XXX [TYPECHECK] diff --git a/neopixel.py b/neopixel.py index 46d9360..93b773f 100644 --- a/neopixel.py +++ b/neopixel.py @@ -2,6 +2,8 @@ # # Copyright (c) 2016 Damien P. George # Copyright (c) 2017 Scott Shawcroft for Adafruit Industries +# Copyright (c) 2019 Carter Nelson +# Copyright (c) 2019 Roy Hooper # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -25,11 +27,9 @@ `neopixel` - NeoPixel strip driver ==================================================== -* Author(s): Damien P. George & Scott Shawcroft +* Author(s): Damien P. George, Scott Shawcroft, Carter Nelson, Roy Hooper """ -import math - try: # imports needed for main NeoPixel class import digitalio @@ -59,9 +59,6 @@ class NeoPixel(_pixelbuf.PixelBuf): - - bpp = None - n = 0 """ A sequence of neopixels. @@ -102,17 +99,18 @@ class NeoPixel(_pixelbuf.PixelBuf): pixels[::2] = [RED] * (len(pixels) // 2) time.sleep(2) """ + def __init__(self, pin, n, *, bpp=3, brightness=1.0, auto_write=True, pixel_order=None): + self.bpp = bpp + self.n = n self._configure(n, bpp, brightness, auto_write, pixel_order) self.pin = digitalio.DigitalInOut(pin) self.pin.direction = digitalio.Direction.OUTPUT - def _configure(self, n, bpp=3, brightness=1.0, auto_write=True, pixel_order=None): - self.bpp = bpp - self.n = n + def _configure(self, n, bpp=3, brightness=1.0, auto_write=True, pixel_order=None): # pylint: disable=too-many-arguments if not pixel_order: pixel_order = GRB if bpp == 3 else GRBW - else: + else: self.bpp = bpp = len(pixel_order) if isinstance(pixel_order, tuple): order_chars = RGBW @@ -159,7 +157,7 @@ def show(self): class NeoPixel_SPI(NeoPixel): """ - A sequence of neopixels. + A sequence of neopixels using SPI. :param ~busio.SPI spi: The SPI bus to output neopixel data on. :param int n: The number of neopixels in the chain @@ -180,7 +178,7 @@ class NeoPixel_SPI(NeoPixel): pixels = neopixel.NeoPixel_SPI(board.SPI(), 10) pixels.fill(0xff0000) """ - #pylint: disable=invalid-name, super-init-not-called + # pylint: disable=invalid-name, super-init-not-called, import-outside-toplevel FREQ = 6400000 # 800kHz * 8, actual may be different TRST = 80e-6 # Reset code low level time From cf56e6084eec50729e8ba6b94a1f4efeace18c36 Mon Sep 17 00:00:00 2001 From: Roy Hooper Date: Sat, 30 Nov 2019 19:37:51 -0500 Subject: [PATCH 09/19] make complaint with pylint 1.9.2 --- neopixel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neopixel.py b/neopixel.py index 93b773f..f69a51d 100644 --- a/neopixel.py +++ b/neopixel.py @@ -178,7 +178,7 @@ class NeoPixel_SPI(NeoPixel): pixels = neopixel.NeoPixel_SPI(board.SPI(), 10) pixels.fill(0xff0000) """ - # pylint: disable=invalid-name, super-init-not-called, import-outside-toplevel + # pylint: disable=invalid-name, super-init-not-called FREQ = 6400000 # 800kHz * 8, actual may be different TRST = 80e-6 # Reset code low level time From 78575b7b76d9cfd8a5d74e2e5635897ef91ccf83 Mon Sep 17 00:00:00 2001 From: Roy Hooper Date: Sat, 30 Nov 2019 19:39:30 -0500 Subject: [PATCH 10/19] make sphinx happy about pypixelbuf not existing yet --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 0f0fa60..51762af 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -15,7 +15,7 @@ 'sphinx.ext.viewcode', ] -autodoc_mock_imports = ["neopixel_write"] +autodoc_mock_imports = ["neopixel_write", "pypixelbuf"] intersphinx_mapping = {'python': ('https://docs.python.org/3.4', None),'CircuitPython': ('https://circuitpython.readthedocs.io/en/latest/', None)} From 3751dd3da79d214f30bb6189a36279f518f771b6 Mon Sep 17 00:00:00 2001 From: Roy Hooper Date: Mon, 2 Dec 2019 14:39:00 -0500 Subject: [PATCH 11/19] add bpp and n properties at the class to avoid AttributeError --- neopixel.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/neopixel.py b/neopixel.py index f69a51d..7f72d9d 100644 --- a/neopixel.py +++ b/neopixel.py @@ -99,6 +99,8 @@ class NeoPixel(_pixelbuf.PixelBuf): pixels[::2] = [RED] * (len(pixels) // 2) time.sleep(2) """ + bpp = None + n = 0 def __init__(self, pin, n, *, bpp=3, brightness=1.0, auto_write=True, pixel_order=None): self.bpp = bpp From d9aabea95f280bc68ca74f9b27e32bc493049799 Mon Sep 17 00:00:00 2001 From: Roy Hooper Date: Wed, 1 Jan 2020 17:28:52 -0500 Subject: [PATCH 12/19] add fill wrapper using the pixelbuf_fill helper --- neopixel.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/neopixel.py b/neopixel.py index 297a81b..5cad850 100644 --- a/neopixel.py +++ b/neopixel.py @@ -151,3 +151,6 @@ def show(self): it may be done asynchronously.""" neopixel_write(self.pin, self.buf) + def fill(self, color): + """Colors all pixels the given ***color***.""" + _pixelbuf.fill(self, color) From cffe2464cdec90262982153ae7651c2f67421aac Mon Sep 17 00:00:00 2001 From: Roy Hooper Date: Wed, 1 Jan 2020 20:16:22 -0500 Subject: [PATCH 13/19] fix import - adafruit_pypixelbuf --- neopixel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neopixel.py b/neopixel.py index 5cad850..1a01f50 100644 --- a/neopixel.py +++ b/neopixel.py @@ -35,7 +35,7 @@ try: import _pixelbuf except ImportError: - import pypixelbuf as _pixelbuf + import adafruit_pypixelbuf as _pixelbuf __version__ = "0.0.0-auto.0" From da77a78c7b774569af68bba6b846a220e1ed0d28 Mon Sep 17 00:00:00 2001 From: Roy Hooper Date: Tue, 7 Jan 2020 12:17:46 -0500 Subject: [PATCH 14/19] switch to actions --- .github/workflows/release.yml | 81 +++++++++++++++++++++++++++++++++++ .travis.yml | 32 -------------- 2 files changed, 81 insertions(+), 32 deletions(-) create mode 100644 .github/workflows/release.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..18efb9c --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,81 @@ +name: Release Actions + +on: + release: + types: [published] + +jobs: + upload-release-assets: + runs-on: ubuntu-latest + steps: + - name: Dump GitHub context + env: + GITHUB_CONTEXT: ${{ toJson(github) }} + run: echo "$GITHUB_CONTEXT" + - name: Translate Repo Name For Build Tools filename_prefix + id: repo-name + run: | + echo ::set-output name=repo-name::$( + echo ${{ github.repository }} | + awk -F '\/' '{ print tolower($2) }' | + tr '_' '-' + ) + - name: Set up Python 3.6 + uses: actions/setup-python@v1 + with: + python-version: 3.6 + - name: Versions + run: | + python3 --version + - name: Checkout Current Repo + uses: actions/checkout@v1 + with: + submodules: true + - name: Checkout tools repo + uses: actions/checkout@v2 + with: + repository: adafruit/actions-ci-circuitpython-libs + path: actions-ci + - name: Install deps + run: | + source actions-ci/install.sh + - name: Build assets + run: circuitpython-build-bundles --filename_prefix ${{ steps.repo-name.outputs.repo-name }} --library_location . + - name: Upload Release Assets + # the 'official' actions version does not yet support dynamically + # supplying asset names to upload. @csexton's version chosen based on + # discussion in the issue below, as its the simplest to implement and + # allows for selecting files with a pattern. + # https://github.com/actions/upload-release-asset/issues/4 + #uses: actions/upload-release-asset@v1.0.1 + uses: csexton/release-asset-action@master + with: + pattern: "bundles/*" + github-token: ${{ secrets.GITHUB_TOKEN }} + + upload-pypi: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Check For setup.py + id: need-pypi + run: | + echo ::set-output name=setup-py::$( find . -wholename './setup.py' ) + - name: Set up Python + if: contains(steps.need-pypi.outputs.setup-py, 'setup.py') + uses: actions/setup-python@v1 + with: + python-version: '3.x' + - name: Install dependencies + if: contains(steps.need-pypi.outputs.setup-py, 'setup.py') + run: | + python -m pip install --upgrade pip + pip install setuptools wheel twine + - name: Build and publish + if: contains(steps.need-pypi.outputs.setup-py, 'setup.py') + env: + TWINE_USERNAME: ${{ secrets.pypi_username }} + TWINE_PASSWORD: ${{ secrets.pypi_password }} + run: | + python setup.py sdist + twine upload dist/* diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 4645d93..0000000 --- a/.travis.yml +++ /dev/null @@ -1,32 +0,0 @@ -dist: trusty -sudo: false -language: python -python: -- '3.6' -cache: - pip: true -deploy: -- provider: releases - api_key: "$GITHUB_TOKEN" - file_glob: true - file: "$TRAVIS_BUILD_DIR/bundles/*" - skip_cleanup: true - overwrite: true - on: - tags: true -- provider: pypi - user: adafruit-travis - on: - tags: true - password: - secure: c8pmry40i83I1bhC6FqDztcB6YUgzOR6tVUwkEczcrOKD6Vu3bKrk1tDIBqiybuOB4Zi76AYn0NGfphqjAyfu0DL+4Sy28f/l8UyWsA61JbftqHA/HAguI872ggPltOf8Qxz7/T4oCpt2hAO3PTvESltlS0tLjWnoSdgs6zz/TSSe5tH97Tm5TfZ4NBVAbcUapqNbWNojZWevH7H/X4BZNoUwdjEOfMdMyJpRm4wjRxLA3okFkC3yPD5z/8TZoOOVicL4cvEIDmLPixd7PmN0Yn4KOWyWjTyVJTD4lcQxYgl+zj8N99eDbosyuBltaU/wzFcz4vuDgVIlS+pBp7TxA9WeE5vt0XwEr0CHx97+0vCO0RzZ3zY3KXUvo9TyIFCMJIOxftpGtTw0ZmnUi3Y2PsJChnQGmLIYGa5KR4e1R3jRlc12xH3+4KzXOfUgRImUfLQIHxuOswiZpT70cbmJSQe+kRhyGvsDr8KsCtbcD7ukACvpEu1QAcNrjkOsESKDcH6vmdJxNDaYR5vqSdQXiSrWBlwqrC662XuXfgqfRkJ/Y/7vWd5m+KFlzfvZV/sMDiqf2T8R6KhNnVa85kXB3Sl5w2vlMSSBXr6xJ4Qp9jlqjcdAuzw6rDm/09J1MDwUGt8ltkGHmP8t6Xjg4tNERCSzGYLLhOc9rT4jAAnhsY= -install: -- pip install -r requirements.txt -- pip install pylint circuitpython-build-tools Sphinx sphinx-rtd-theme -- pip install --force-reinstall pylint==1.9.2 -script: -- pylint neopixel.py -- ([[ ! -d "examples" ]] || pylint --disable=missing-docstring,invalid-name examples/*.py) -- circuitpython-build-bundles --filename_prefix adafruit-circuitpython-neopixel --library_location - . -- cd docs && sphinx-build -E -W -b html . _build/html && cd .. From 7dd35d82b875244375c9ee4a203588aa335fa1b4 Mon Sep 17 00:00:00 2001 From: Roy Hooper Date: Tue, 7 Jan 2020 12:19:13 -0500 Subject: [PATCH 15/19] add pypixelbuf dependency --- requirements.txt | 1 + setup.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index edf9394..5feab09 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ Adafruit-Blinka +adafruit-circuitpython-pypixelbuf diff --git a/setup.py b/setup.py index b2eb264..19b9d72 100644 --- a/setup.py +++ b/setup.py @@ -34,7 +34,7 @@ author='Adafruit Industries & Damien P. George', author_email='circuitpython@adafruit.com', - install_requires=['Adafruit-Blinka'], + install_requires=['Adafruit-Blinka', 'adafruit-circuitpython-pypixelbuf'], # Choose your license license='MIT', From 7db0c9b5f5af37215c83328d3455351a81b9b95f Mon Sep 17 00:00:00 2001 From: Roy Hooper Date: Tue, 7 Jan 2020 12:21:07 -0500 Subject: [PATCH 16/19] Revert "switch to actions" This reverts commit da77a78c7b774569af68bba6b846a220e1ed0d28. --- .github/workflows/release.yml | 81 ----------------------------------- .travis.yml | 32 ++++++++++++++ 2 files changed, 32 insertions(+), 81 deletions(-) delete mode 100644 .github/workflows/release.yml create mode 100644 .travis.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 18efb9c..0000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,81 +0,0 @@ -name: Release Actions - -on: - release: - types: [published] - -jobs: - upload-release-assets: - runs-on: ubuntu-latest - steps: - - name: Dump GitHub context - env: - GITHUB_CONTEXT: ${{ toJson(github) }} - run: echo "$GITHUB_CONTEXT" - - name: Translate Repo Name For Build Tools filename_prefix - id: repo-name - run: | - echo ::set-output name=repo-name::$( - echo ${{ github.repository }} | - awk -F '\/' '{ print tolower($2) }' | - tr '_' '-' - ) - - name: Set up Python 3.6 - uses: actions/setup-python@v1 - with: - python-version: 3.6 - - name: Versions - run: | - python3 --version - - name: Checkout Current Repo - uses: actions/checkout@v1 - with: - submodules: true - - name: Checkout tools repo - uses: actions/checkout@v2 - with: - repository: adafruit/actions-ci-circuitpython-libs - path: actions-ci - - name: Install deps - run: | - source actions-ci/install.sh - - name: Build assets - run: circuitpython-build-bundles --filename_prefix ${{ steps.repo-name.outputs.repo-name }} --library_location . - - name: Upload Release Assets - # the 'official' actions version does not yet support dynamically - # supplying asset names to upload. @csexton's version chosen based on - # discussion in the issue below, as its the simplest to implement and - # allows for selecting files with a pattern. - # https://github.com/actions/upload-release-asset/issues/4 - #uses: actions/upload-release-asset@v1.0.1 - uses: csexton/release-asset-action@master - with: - pattern: "bundles/*" - github-token: ${{ secrets.GITHUB_TOKEN }} - - upload-pypi: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - - name: Check For setup.py - id: need-pypi - run: | - echo ::set-output name=setup-py::$( find . -wholename './setup.py' ) - - name: Set up Python - if: contains(steps.need-pypi.outputs.setup-py, 'setup.py') - uses: actions/setup-python@v1 - with: - python-version: '3.x' - - name: Install dependencies - if: contains(steps.need-pypi.outputs.setup-py, 'setup.py') - run: | - python -m pip install --upgrade pip - pip install setuptools wheel twine - - name: Build and publish - if: contains(steps.need-pypi.outputs.setup-py, 'setup.py') - env: - TWINE_USERNAME: ${{ secrets.pypi_username }} - TWINE_PASSWORD: ${{ secrets.pypi_password }} - run: | - python setup.py sdist - twine upload dist/* diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..4645d93 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,32 @@ +dist: trusty +sudo: false +language: python +python: +- '3.6' +cache: + pip: true +deploy: +- provider: releases + api_key: "$GITHUB_TOKEN" + file_glob: true + file: "$TRAVIS_BUILD_DIR/bundles/*" + skip_cleanup: true + overwrite: true + on: + tags: true +- provider: pypi + user: adafruit-travis + on: + tags: true + password: + secure: c8pmry40i83I1bhC6FqDztcB6YUgzOR6tVUwkEczcrOKD6Vu3bKrk1tDIBqiybuOB4Zi76AYn0NGfphqjAyfu0DL+4Sy28f/l8UyWsA61JbftqHA/HAguI872ggPltOf8Qxz7/T4oCpt2hAO3PTvESltlS0tLjWnoSdgs6zz/TSSe5tH97Tm5TfZ4NBVAbcUapqNbWNojZWevH7H/X4BZNoUwdjEOfMdMyJpRm4wjRxLA3okFkC3yPD5z/8TZoOOVicL4cvEIDmLPixd7PmN0Yn4KOWyWjTyVJTD4lcQxYgl+zj8N99eDbosyuBltaU/wzFcz4vuDgVIlS+pBp7TxA9WeE5vt0XwEr0CHx97+0vCO0RzZ3zY3KXUvo9TyIFCMJIOxftpGtTw0ZmnUi3Y2PsJChnQGmLIYGa5KR4e1R3jRlc12xH3+4KzXOfUgRImUfLQIHxuOswiZpT70cbmJSQe+kRhyGvsDr8KsCtbcD7ukACvpEu1QAcNrjkOsESKDcH6vmdJxNDaYR5vqSdQXiSrWBlwqrC662XuXfgqfRkJ/Y/7vWd5m+KFlzfvZV/sMDiqf2T8R6KhNnVa85kXB3Sl5w2vlMSSBXr6xJ4Qp9jlqjcdAuzw6rDm/09J1MDwUGt8ltkGHmP8t6Xjg4tNERCSzGYLLhOc9rT4jAAnhsY= +install: +- pip install -r requirements.txt +- pip install pylint circuitpython-build-tools Sphinx sphinx-rtd-theme +- pip install --force-reinstall pylint==1.9.2 +script: +- pylint neopixel.py +- ([[ ! -d "examples" ]] || pylint --disable=missing-docstring,invalid-name examples/*.py) +- circuitpython-build-bundles --filename_prefix adafruit-circuitpython-neopixel --library_location + . +- cd docs && sphinx-build -E -W -b html . _build/html && cd .. From 2fb1db5757e2c2ea157c74a760a4173f29b8805c Mon Sep 17 00:00:00 2001 From: Roy Hooper Date: Tue, 7 Jan 2020 18:57:36 -0500 Subject: [PATCH 17/19] remove _configure - no longer needed --- neopixel.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/neopixel.py b/neopixel.py index 1a01f50..aca77d5 100644 --- a/neopixel.py +++ b/neopixel.py @@ -100,11 +100,7 @@ class NeoPixel(_pixelbuf.PixelBuf): def __init__(self, pin, n, *, bpp=3, brightness=1.0, auto_write=True, pixel_order=None): self.bpp = bpp self.n = n - self._configure(n, bpp, brightness, auto_write, pixel_order) - self.pin = digitalio.DigitalInOut(pin) - self.pin.direction = digitalio.Direction.OUTPUT - def _configure(self, n, bpp=3, brightness=1.0, auto_write=True, pixel_order=None): # pylint: disable=too-many-arguments if not pixel_order: pixel_order = GRB if bpp == 3 else GRBW else: @@ -122,6 +118,9 @@ def _configure(self, n, bpp=3, brightness=1.0, auto_write=True, pixel_order=None byteorder=pixel_order, auto_write=auto_write) + self.pin = digitalio.DigitalInOut(pin) + self.pin.direction = digitalio.Direction.OUTPUT + def deinit(self): """Blank out the NeoPixels and release the pin.""" self.fill(0) From b01709c7c7877e03debfc9213f3be53997c836b6 Mon Sep 17 00:00:00 2001 From: Roy Hooper Date: Wed, 8 Jan 2020 17:59:34 -0500 Subject: [PATCH 18/19] remove pypixelbuf from mock imports --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 51762af..0f0fa60 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -15,7 +15,7 @@ 'sphinx.ext.viewcode', ] -autodoc_mock_imports = ["neopixel_write", "pypixelbuf"] +autodoc_mock_imports = ["neopixel_write"] intersphinx_mapping = {'python': ('https://docs.python.org/3.4', None),'CircuitPython': ('https://circuitpython.readthedocs.io/en/latest/', None)} From f406096804038d017bd5c55a8be52e8b5db749de Mon Sep 17 00:00:00 2001 From: Roy Hooper Date: Thu, 9 Jan 2020 12:38:48 -0500 Subject: [PATCH 19/19] undo change to .pylintrc --- .pylintrc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.pylintrc b/.pylintrc index 039eaec..cb8d23d 100644 --- a/.pylintrc +++ b/.pylintrc @@ -119,8 +119,7 @@ spelling-store-unknown-words=no [MISCELLANEOUS] # List of note tags to take in consideration, separated by a comma. -# notes=FIXME,XXX,TODO -notes=FIXME,XXX +notes=FIXME,XXX,TODO [TYPECHECK]