/ adafruit_pixie.py
adafruit_pixie.py
  1  # The MIT License (MIT)
  2  #
  3  # Copyright (c) 2016 Damien P. George (original Neopixel object)
  4  # Copyright (c) 2018 Ladyada
  5  #
  6  # Permission is hereby granted, free of charge, to any person obtaining a copy
  7  # of this software and associated documentation files (the "Software"), to deal
  8  # in the Software without restriction, including without limitation the rights
  9  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 10  # copies of the Software, and to permit persons to whom the Software is
 11  # furnished to do so, subject to the following conditions:
 12  #
 13  # The above copyright notice and this permission notice shall be included in
 14  # all copies or substantial portions of the Software.
 15  #
 16  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 17  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 18  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 19  # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 20  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 21  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 22  # THE SOFTWARE.
 23  
 24  """
 25  `adafruit_pixie` - Pixie LED driver
 26  ====================================================
 27  * Author(s): Damien P. George, Limor Fried, Kattni Rembor
 28  """
 29  
 30  import time
 31  import math
 32  
 33  __version__ = "0.0.0-auto.0"
 34  __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Pixie.git"
 35  
 36  
 37  class Pixie:
 38      """
 39      PIxie LEDs.
 40  
 41      :param uart: The UART object.
 42      :param int n: The number of Pixies in the chain.
 43      :param float brightness: Brightness of the pixels between 0.0 and 1.0.
 44      :param bool auto_write: True if the Pixies should immediately change when
 45          set. If False, `show` must be called explicitly.
 46  
 47      Example for two Pixie LEDs chained:
 48  
 49      .. code_block::python
 50  
 51          import time
 52          import board
 53          import busio
 54          import adafruit_pixie
 55  
 56          uart = busio.UART(board.TX, rx=None, baudrate=115200)
 57          pixies = adafruit_pixie.Pixie(uart, 2, brightness=0.5)
 58  
 59          while True:
 60              pixies.fill((255, 0, 0))
 61              time.sleep(1)
 62              pixies[0] = (0, 255, 0)
 63              pixies[1] = (0, 0, 255)
 64              time.sleep(1)
 65      """
 66  
 67      def __init__(self, uart, n, *, brightness=1.0, auto_write=True):
 68          self._uart = uart
 69          self._n = n
 70          self._buf = bytearray(self._n * 3)
 71          # Set auto_write to False temporarily so brightness setter does _not_
 72          # call show() while in __init__.
 73          self.auto_write = False
 74          self._brightness = brightness
 75          self.auto_write = auto_write
 76  
 77      def _set_item(self, index, value):
 78          if index < 0:
 79              index += len(self)
 80          if index >= self._n or index < 0:
 81              raise IndexError
 82          offset = index * 3
 83          r = 0
 84          g = 0
 85          b = 0
 86          if isinstance(value, int):
 87              r = value >> 16
 88              g = (value >> 8) & 0xFF
 89              b = value & 0xFF
 90          elif len(value) == 3:
 91              r, g, b = value
 92          self._buf[offset + 0] = r
 93          self._buf[offset + 1] = g
 94          self._buf[offset + 2] = b
 95  
 96      def __setitem__(self, index, val):
 97          if isinstance(index, slice):
 98              start, stop, step = index.indices(len(self._buf) // 3)
 99              length = stop - start
100              if step != 0:
101                  length = math.ceil(length / step)
102              if len(val) != length:
103                  raise ValueError("Slice and input sequence size do not match.")
104              for val_i, in_i in enumerate(range(start, stop, step)):
105                  self._set_item(in_i, val[val_i])
106          else:
107              self._set_item(index, val)
108  
109          if self.auto_write:
110              self.show()
111  
112      def __len__(self):
113          return len(self._buf) // 3
114  
115      @property
116      def brightness(self):
117          """Overall brightness of the pixel"""
118          return self._brightness
119  
120      @brightness.setter
121      def brightness(self, brightness):
122          self._brightness = min(max(brightness, 0.0), 1.0)
123          if self.auto_write:
124              self.show()
125  
126      def fill(self, color):
127          """Colors all pixels the given ***color***."""
128          auto_write = self.auto_write
129          self.auto_write = False
130          for i in range(self._n):
131              self[i] = color
132          if auto_write:
133              self.show()
134          self.auto_write = auto_write
135  
136      def show(self):
137          """
138          Shows the new colors on the pixels themselves if they haven't already
139          been autowritten.
140          """
141          self._uart.write(bytes([int(i * self.brightness) for i in self._buf]))
142          time.sleep(0.005)