From 3d3a039e396f6c1c46686c1537eb5183beddc951 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 5 Dec 2017 18:11:15 -0800 Subject: [PATCH 01/12] Add RTD.yaml and requirements as cookiecutter would generate them. --- readthedocs.yml | 3 +++ requirements.txt | 0 2 files changed, 3 insertions(+) create mode 100644 readthedocs.yml create mode 100644 requirements.txt diff --git a/readthedocs.yml b/readthedocs.yml new file mode 100644 index 0000000..f4243ad --- /dev/null +++ b/readthedocs.yml @@ -0,0 +1,3 @@ +python: + version: 3 +requirements_file: requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e69de29 From 7997057de145b9900426379772f46718bd563529 Mon Sep 17 00:00:00 2001 From: mrmcwethy Date: Thu, 8 Feb 2018 12:56:59 -0700 Subject: [PATCH 02/12] added examples folder and .py file --- examples/randomcolor.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 examples/randomcolor.py diff --git a/examples/randomcolor.py b/examples/randomcolor.py new file mode 100644 index 0000000..fe86411 --- /dev/null +++ b/examples/randomcolor.py @@ -0,0 +1,28 @@ +import time +import random +import board +import adafruit_dotstar as dotstar + +# One pixel connected internally on a GEMMA M0 +dots = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2) + +# With a Dotstar Digital LEB Strip with 30 lights +#dots = dotstar.DotStar(board.SCK, board.MOSI, 30, brightness=0.2) + +######################### HELPERS ############################## + +# a random color 0 -> 224 +def rndc(): + return random.randrange(0, 7) * 32 + +######################### MAIN LOOP ############################## +n = len(dots) +while True: + #fill each dot with a random color1 + for dot in range(n): + dots[dot] = (rndc(), rndc(), rndc()) + + # show all dots in strip + dots.show() + + time.sleep(.25) From e64dd6febadc01988a6163f821201708cd8fd98b Mon Sep 17 00:00:00 2001 From: mrmcwethy Date: Fri, 9 Feb 2018 09:08:44 -0700 Subject: [PATCH 03/12] improved code sample --- examples/randomcolor.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/randomcolor.py b/examples/randomcolor.py index fe86411..a21f182 100644 --- a/examples/randomcolor.py +++ b/examples/randomcolor.py @@ -12,15 +12,15 @@ ######################### HELPERS ############################## # a random color 0 -> 224 -def rndc(): +def random_color(): return random.randrange(0, 7) * 32 ######################### MAIN LOOP ############################## -n = len(dots) +n_dots = len(dots) while True: - #fill each dot with a random color1 - for dot in range(n): - dots[dot] = (rndc(), rndc(), rndc()) + #fill each dot with a random color + for dot in range(n_dots): + dots[dot] = (random_color(), random_color(), random_color()) # show all dots in strip dots.show() From 503e85456eb41c5a16ce26ca5930fba421ccad61 Mon Sep 17 00:00:00 2001 From: Matt Trentini Date: Sat, 10 Feb 2018 21:21:49 +1100 Subject: [PATCH 04/12] Changing brightness will now update the strip if auto_write is True. See Issue #10. --- adafruit_dotstar.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/adafruit_dotstar.py b/adafruit_dotstar.py index e2a04f2..5bcc3d6 100755 --- a/adafruit_dotstar.py +++ b/adafruit_dotstar.py @@ -95,6 +95,9 @@ def __init__(self, clock, data, n, *, brightness=1.0, auto_write=True): for i in range(self.end_header_index, len(self._buf)): self._buf[i] = 0xff self._brightness = 1.0 + # 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 @@ -182,6 +185,8 @@ def brightness(self): @brightness.setter def brightness(self, brightness): self._brightness = min(max(brightness, 0.0), 1.0) + if self.auto_write: + self.show() def fill(self, color): """Colors all pixels the given ***color***.""" From a14bd1f182bf61dbb107f9c5045466399f7ee37d Mon Sep 17 00:00:00 2001 From: sommersoft Date: Sat, 24 Feb 2018 20:19:07 -0600 Subject: [PATCH 05/12] renamed example --- examples/{randomcolor.py => dotstar_simpletest.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{randomcolor.py => dotstar_simpletest.py} (100%) diff --git a/examples/randomcolor.py b/examples/dotstar_simpletest.py similarity index 100% rename from examples/randomcolor.py rename to examples/dotstar_simpletest.py From 3d40f99b45b94df157c9d062ddbe1304afc67983 Mon Sep 17 00:00:00 2001 From: sommersoft Date: Sat, 24 Feb 2018 20:24:09 -0600 Subject: [PATCH 06/12] setup docs folder --- docs/_static/favicon.ico | Bin 0 -> 4414 bytes api.rst => docs/api.rst | 0 conf.py => docs/conf.py | 15 ++++++++++--- docs/examples.rst | 8 +++++++ docs/index.rst | 47 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 docs/_static/favicon.ico rename api.rst => docs/api.rst (100%) rename conf.py => docs/conf.py (90%) create mode 100644 docs/examples.rst create mode 100644 docs/index.rst diff --git a/docs/_static/favicon.ico b/docs/_static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..5aca98376a1f7e593ebd9cf41a808512c2135635 GIT binary patch literal 4414 zcmd^BX;4#F6n=SG-XmlONeGrD5E6J{RVh+e928U#MG!$jWvO+UsvWh`x&VqGNx*en zx=qox7Dqv{kPwo%fZC$dDwVpRtz{HzTkSs8QhG0)%Y=-3@Kt!4ag|JcIo?$-F|?bXVS9UDUyev>MVZQ(H8K4#;BQW-t2CPorj8^KJrMX}QK zp+e<;4ldpXz~=)2GxNy811&)gt-}Q*yVQpsxr@VMoA##{)$1~=bZ1MmjeFw?uT(`8 z^g=09<=zW%r%buwN%iHtuKSg|+r7HkT0PYN*_u9k1;^Ss-Z!RBfJ?Un4w(awqp2b3 z%+myoFis_lTlCrGx2z$0BQdh+7?!JK#9K9@Z!VrG zNj6gK5r(b4?YDOLw|DPRoN7bdP{(>GEG41YcN~4r_SUHU2hgVtUwZG@s%edC;k7Sn zC)RvEnlq~raE2mY2ko64^m1KQL}3riixh?#J{o)IT+K-RdHae2eRX91-+g!y`8^># z-zI0ir>P%Xon)!@xp-BK2bDYUB9k613NRrY6%lVjbFcQc*pRqiK~8xtkNPLxt}e?&QsTB}^!39t_%Qb)~Ukn0O%iC;zt z<&A-y;3h++)>c1br`5VFM~5(83!HKx$L+my8sW_c#@x*|*vB1yU)_dt3vH;2hqPWx zAl^6@?ipx&U7pf`a*>Yq6C85nb+B=Fnn+(id$W#WB^uHAcZVG`qg;rWB}ubvi(Y>D z$ei>REw$#xp0SHAd^|1hq&9HJ=jKK8^zTH~nk)G?yUcmTh9vUM6Y0LMw4(gYVY$D$ zGl&WY&H<)BbJ&3sYbKjx1j^=3-0Q#f^}(aP1?8^`&FUWMp|rmtpK)bLQ1Zo?^s4jqK=Lfg*9&geMGVQ z#^-*!V`fG@;H&{M9S8%+;|h&Qrxym0Ar>WT4BCVLR8cGXF=JmEYN(sNT(9vl+S|%g z8r7nXQ(95i^`=+XHo|){$vf2$?=`F$^&wFlYXyXg$B{a>$-Fp+V}+D;9k=~Xl~?C4 zAB-;RKXdUzBJE{V&d&%R>aEfFe;vxqI$0@hwVM}gFeQR@j}a>DDxR+n+-*6|_)k%% z*mSpDV|=5I9!&VC&9tD%fcVygWZV!iIo2qFtm#!*(s|@ZT33*Ad;+<|3^+yrp*;oH zBSYLV(H1zTU?2WjrCQoQW)Z>J2a=dTriuvezBmu16`tM2fm7Q@d4^iqII-xFpwHGI zn9CL}QE*1vdj2PX{PIuqOe5dracsciH6OlAZATvE8rj6ykqdIjal2 z0S0S~PwHb-5?OQ-tU-^KTG@XNrEVSvo|HIP?H;7ZhYeZkhSqh-{reE!5di;1zk$#Y zCe7rOnlzFYJ6Z#Hm$GoidKB=2HBCwm`BbZVeZY4ukmG%1uz7p2URs6c9j-Gjj^oQV zsdDb3@k2e`C$1I5ML5U0Qs0C1GAp^?!*`=|Nm(vWz3j*j*8ucum2;r0^-6Aca=Gv) zc%}&;!+_*S2tlnnJnz0EKeRmw-Y!@9ob!XQBwiv}^u9MkaXHvM=!<3YX;+2#5Cj5pp?FEK750S3BgeSDtaE^ zXUM@xoV6yBFKfzvY20V&Lr0yC + +.. toctree:: + :caption: Other Links + + Download + CircuitPython Reference Documentation + CircuitPython Support Forum + Discord Chat + Adafruit Learning System + Adafruit Blog + Adafruit Store + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` From 25f5ec980794c8889ee79b537ab03c46e9c803fa Mon Sep 17 00:00:00 2001 From: sommersoft Date: Sat, 24 Feb 2018 20:26:40 -0600 Subject: [PATCH 07/12] updated .travis & .readthedocs yml --- readthedocs.yml => .readthedocs.yml | 0 .travis.yml | 6 ++++-- 2 files changed, 4 insertions(+), 2 deletions(-) rename readthedocs.yml => .readthedocs.yml (100%) diff --git a/readthedocs.yml b/.readthedocs.yml similarity index 100% rename from readthedocs.yml rename to .readthedocs.yml diff --git a/.travis.yml b/.travis.yml index 8de8807..58d3063 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,15 +16,17 @@ deploy: provider: releases api_key: $GITHUB_TOKEN file_glob: true - file: bundles/* + file: $TRAVIS_BUILD_DIR/bundles/* skip_cleanup: true + overwrite: true on: tags: true install: - - pip install pylint circuitpython-travis-build-tools + - pip install pylint circuitpython-build-tools Sphinx sphinx-rtd-theme script: - pylint adafruit_dotstar.py - ([[ ! -d "examples" ]] || pylint --disable=missing-docstring,invalid-name examples/*.py) - circuitpython-build-bundles --filename_prefix adafruit-circuitpython-dotstar --library_location . + - cd docs && sphinx-build -E -W -b html . _build/html From 85327027c9ddabf7ea00dc5e4ac87a3585ccb5c4 Mon Sep 17 00:00:00 2001 From: sommersoft Date: Sat, 24 Feb 2018 20:28:29 -0600 Subject: [PATCH 08/12] updated README --- README.rst | 49 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index a1e5190..1444f9d 100644 --- a/README.rst +++ b/README.rst @@ -56,10 +56,49 @@ Contributions are welcome! Please read our `Code of Conduct `_ before contributing to help this project stay welcoming. -API Reference -============= +Building locally +================ + +To build this library locally you'll need to install the +`circuitpython-build-tools `_ package. + +.. code-block:: shell + + python3 -m venv .env + source .env/bin/activate + pip install circuitpython-build-tools + +Once installed, make sure you are in the virtual environment: + +.. code-block:: shell + + source .env/bin/activate + +Then run the build: + +.. code-block:: shell + + circuitpython-build-bundles --filename_prefix adafruit-circuitpython-dotstar --library_location . + +Sphinx documentation +----------------------- + +Sphinx is used to build the documentation based on rST files and comments in the code. First, +install dependencies (feel free to reuse the virtual environment from above): + +.. code-block:: shell + + python3 -m venv .env + source .env/bin/activate + pip install Sphinx sphinx-rtd-theme + +Now, once you have the virtual environment activated: + +.. code-block:: shell -.. toctree:: - :maxdepth: 2 + cd docs + sphinx-build -E -W -b html . _build/html - api +This will output the documentation to ``docs/_build/html``. Open the index.html in your browser to +view them. It will also (due to -W) error out on any warning like Travis will. This is a good way to +locally verify it will pass. From 2d6ce1535b561ac758c5f8ff6a8b96d97a19c11a Mon Sep 17 00:00:00 2001 From: sommersoft Date: Sat, 10 Mar 2018 09:43:07 -0600 Subject: [PATCH 09/12] updated README; added Travis badge --- README.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.rst b/README.rst index 1444f9d..9ecd1f9 100644 --- a/README.rst +++ b/README.rst @@ -10,6 +10,10 @@ Adafruit CircuitPython DotStar :target: https://adafru.it/discord :alt: Discord +.. image:: https://travis-ci.org/adafruit/Adafruit_CircuitPython_DotStar.svg?branch=master + :target: https://travis-ci.org/adafruit/Adafruit_CircuitPython_DotStar + :alt: Build Status + Higher level DotStar driver that presents the strip as a sequence. It is the same api as the `NeoPixel library `_. From c033bd45211b4101c121e2a6cea6aa1905c684fa Mon Sep 17 00:00:00 2001 From: mcscope Date: Mon, 14 May 2018 09:17:40 -0700 Subject: [PATCH 10/12] Support Color Order setting --- adafruit_dotstar.py | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/adafruit_dotstar.py b/adafruit_dotstar.py index 5bcc3d6..f2050bf 100755 --- a/adafruit_dotstar.py +++ b/adafruit_dotstar.py @@ -36,6 +36,15 @@ __version__ = "0.0.0-auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DotStar.git" +# Pixel color order constants +RGB = (0, 1, 2) +RBG = (0, 2, 1) +GRB = (1, 0, 2) +GBR = (1, 2, 0) +BRG = (2, 0, 1) +BGR = (2, 1, 0) + + class DotStar: """ A sequence of dotstars. @@ -46,6 +55,9 @@ class DotStar: :param float brightness: Brightness of the pixels between 0.0 and 1.0 :param bool auto_write: True if the dotstars should immediately change when set. If False, `show` must be called explicitly. + :param tuple pixel_order: Set the pixel order on the strip - different + strips implement this differently. If you send red, and it looks blue + or green on the strip, modify this! It should be one of the values above Example for Gemma M0: @@ -63,7 +75,7 @@ class DotStar: time.sleep(2) """ - def __init__(self, clock, data, n, *, brightness=1.0, auto_write=True): + def __init__(self, clock, data, n, *, brightness=1.0, auto_write=True, pixel_order=BGR): self._spi = None try: self._spi = busio.SPI(clock, MOSI=data) @@ -84,7 +96,7 @@ def __init__(self, clock, data, n, *, brightness=1.0, auto_write=True): self.end_header_size += 1 self._buf = bytearray(n * 4 + self.start_header_size + self.end_header_size) self.end_header_index = len(self._buf) - self.end_header_size - + self.pixel_order = pixel_order # Four empty bytes to start. for i in range(self.start_header_size): self._buf[i] = 0x00 @@ -125,23 +137,18 @@ def __repr__(self): def _set_item(self, index, value): offset = index * 4 + self.start_header_size - r = 0 - g = 0 - b = 0 + rbg = value if isinstance(value, int): - r = value >> 16 - g = (value >> 8) & 0xff - b = value & 0xff - else: - r, g, b = value + rgb = (value >> 16, (value >> 8) & 0xff, value & 0xff) + # Each pixel starts with 0xFF, then red/green/blue. Although the data # sheet suggests using a global brightness in the first byte, we don't # do that because it causes further issues with persistence of vision # projects. self._buf[offset] = 0xff # redundant; should already be set - self._buf[offset + 1] = b - self._buf[offset + 2] = g - self._buf[offset + 3] = r + self._buf[offset + 1] = rgb[self.pixel_order[0]] + self._buf[offset + 2] = rgb[self.pixel_order[1]] + self._buf[offset + 3] = rgb[self.pixel_order[2]] def __setitem__(self, index, val): if isinstance(index, slice): @@ -220,7 +227,7 @@ def show(self): for i in range(self.start_header_size): buf[i] = 0x00 for i in range(self.start_header_size, self.end_header_index): - buf[i] = self._buf[i] if i %4 == 0 else int(self._buf[i] * self._brightness) + buf[i] = self._buf[i] if i % 4 == 0 else int(self._buf[i] * self._brightness) # Four 0xff bytes at the end. for i in range(self.end_header_index, len(buf)): buf[i] = 0xff From a8d40106749ec0e73caba8590e12ab8d098e2080 Mon Sep 17 00:00:00 2001 From: mcscope Date: Mon, 14 May 2018 10:21:49 -0700 Subject: [PATCH 11/12] Typo --- adafruit_dotstar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_dotstar.py b/adafruit_dotstar.py index f2050bf..611bf1f 100755 --- a/adafruit_dotstar.py +++ b/adafruit_dotstar.py @@ -137,7 +137,7 @@ def __repr__(self): def _set_item(self, index, value): offset = index * 4 + self.start_header_size - rbg = value + rgb = value if isinstance(value, int): rgb = (value >> 16, (value >> 8) & 0xff, value & 0xff) From 1b877e1c61cda5df5687208ed7c0c94bace88a66 Mon Sep 17 00:00:00 2001 From: mcscope Date: Mon, 14 May 2018 11:01:16 -0700 Subject: [PATCH 12/12] start header doesn't need to be instance val --- adafruit_dotstar.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/adafruit_dotstar.py b/adafruit_dotstar.py index 611bf1f..f032b3a 100755 --- a/adafruit_dotstar.py +++ b/adafruit_dotstar.py @@ -36,6 +36,8 @@ __version__ = "0.0.0-auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DotStar.git" +START_HEADER_SIZE = 4 + # Pixel color order constants RGB = (0, 1, 2) RBG = (0, 2, 1) @@ -89,19 +91,18 @@ def __init__(self, clock, data, n, *, brightness=1.0, auto_write=True, pixel_ord self.cpin.direction = digitalio.Direction.OUTPUT self.cpin.value = False self._n = n - self.start_header_size = 4 # Supply one extra clock cycle for each two pixels in the strip. self.end_header_size = n // 16 if n % 16 != 0: self.end_header_size += 1 - self._buf = bytearray(n * 4 + self.start_header_size + self.end_header_size) + self._buf = bytearray(n * 4 + START_HEADER_SIZE + self.end_header_size) self.end_header_index = len(self._buf) - self.end_header_size self.pixel_order = pixel_order # Four empty bytes to start. - for i in range(self.start_header_size): + for i in range(START_HEADER_SIZE): self._buf[i] = 0x00 # Mark the beginnings of each pixel. - for i in range(self.start_header_size, self.end_header_index, 4): + for i in range(START_HEADER_SIZE, self.end_header_index, 4): self._buf[i] = 0xff # 0xff bytes at the end. for i in range(self.end_header_index, len(self._buf)): @@ -116,7 +117,7 @@ def __init__(self, clock, data, n, *, brightness=1.0, auto_write=True, pixel_ord def deinit(self): """Blank out the DotStars and release the resources.""" self.auto_write = False - for i in range(self.start_header_size, self.end_header_index): + for i in range(START_HEADER_SIZE, self.end_header_index): if i % 4 != 0: self._buf[i] = 0 self.show() @@ -136,7 +137,7 @@ def __repr__(self): return "[" + ", ".join([str(x) for x in self]) + "]" def _set_item(self, index, value): - offset = index * 4 + self.start_header_size + offset = index * 4 + START_HEADER_SIZE rgb = value if isinstance(value, int): rgb = (value >> 16, (value >> 8) & 0xff, value & 0xff) @@ -171,14 +172,14 @@ def __getitem__(self, index): out = [] for in_i in range(*index.indices(len(self._buf) // 4)): out.append( - tuple(self._buf[in_i * 4 + (3 - i) + self.start_header_size] for i in range(3))) + tuple(self._buf[in_i * 4 + (3 - i) + START_HEADER_SIZE] for i in range(3))) return out if index < 0: index += len(self) if index >= self._n or index < 0: raise IndexError offset = index * 4 - return tuple(self._buf[offset + (3 - i) + self.start_header_size] + return tuple(self._buf[offset + (3 - i) + START_HEADER_SIZE] for i in range(3)) def __len__(self): @@ -224,9 +225,9 @@ def show(self): if self.brightness < 1.0: buf = bytearray(self._buf) # Four empty bytes to start. - for i in range(self.start_header_size): + for i in range(START_HEADER_SIZE): buf[i] = 0x00 - for i in range(self.start_header_size, self.end_header_index): + for i in range(START_HEADER_SIZE, self.end_header_index): buf[i] = self._buf[i] if i % 4 == 0 else int(self._buf[i] * self._brightness) # Four 0xff bytes at the end. for i in range(self.end_header_index, len(buf)):