/ adafruit_ht16k33 / ht16k33.py
ht16k33.py
  1  # The MIT License (MIT)
  2  #
  3  # Copyright (c) 2016 Radomir Dopieralski & Tony DiCola for Adafruit Industries
  4  #
  5  # Permission is hereby granted, free of charge, to any person obtaining a copy
  6  # of this software and associated documentation files (the "Software"), to deal
  7  # in the Software without restriction, including without limitation the rights
  8  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9  # copies of the Software, and to permit persons to whom the Software is
 10  # furnished to do so, subject to the following conditions:
 11  #
 12  # The above copyright notice and this permission notice shall be included in all
 13  # copies or substantial portions of the Software.
 14  #
 15  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18  # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 21  # SOFTWARE.
 22  
 23  """
 24  `adafruit_ht16k33.ht16k33`
 25  ===========================
 26  
 27  * Authors: Radomir Dopieralski & Tony DiCola for Adafruit Industries
 28  
 29  """
 30  
 31  from adafruit_bus_device import i2c_device
 32  from micropython import const
 33  
 34  __version__ = "0.0.0-auto.0"
 35  __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_HT16K33.git"
 36  
 37  _HT16K33_BLINK_CMD = const(0x80)
 38  _HT16K33_BLINK_DISPLAYON = const(0x01)
 39  _HT16K33_CMD_BRIGHTNESS = const(0xE0)
 40  _HT16K33_OSCILATOR_ON = const(0x21)
 41  
 42  
 43  class HT16K33:
 44      """
 45      The base class for all displays. Contains common methods.
 46  
 47      :param int address: The I2C addess of the HT16K33.
 48      :param bool auto_write: True if the display should immediately change when
 49          set. If False, `show` must be called explicitly.
 50      :param float brightness: 0.0 - 1.0 default brightness level.
 51      """
 52  
 53      def __init__(self, i2c, address=0x70, auto_write=True, brightness=1.0):
 54          self.i2c_device = i2c_device.I2CDevice(i2c, address)
 55          self._temp = bytearray(1)
 56          self._buffer = bytearray(17)
 57          self._auto_write = auto_write
 58          self.fill(0)
 59          self._write_cmd(_HT16K33_OSCILATOR_ON)
 60          self._blink_rate = None
 61          self._brightness = None
 62          self.blink_rate = 0
 63          self.brightness = brightness
 64  
 65      def _write_cmd(self, byte):
 66          self._temp[0] = byte
 67          with self.i2c_device:
 68              self.i2c_device.write(self._temp)
 69  
 70      @property
 71      def blink_rate(self):
 72          """The blink rate. Range 0-3."""
 73          return self._blink_rate
 74  
 75      @blink_rate.setter
 76      def blink_rate(self, rate=None):
 77          if not 0 <= rate <= 3:
 78              raise ValueError("Blink rate must be an integer in the range: 0-3")
 79          rate = rate & 0x03
 80          self._blink_rate = rate
 81          self._write_cmd(_HT16K33_BLINK_CMD | _HT16K33_BLINK_DISPLAYON | rate << 1)
 82  
 83      @property
 84      def brightness(self):
 85          """The brightness. Range 0.0-1.0"""
 86          return self._brightness
 87  
 88      @brightness.setter
 89      def brightness(self, brightness):
 90          if not 0.0 <= brightness <= 1.0:
 91              raise ValueError(
 92                  "Brightness must be a decimal number in the range: 0.0-1.0"
 93              )
 94  
 95          self._brightness = brightness
 96          xbright = round(15 * brightness)
 97          xbright = xbright & 0x0F
 98          self._write_cmd(_HT16K33_CMD_BRIGHTNESS | xbright)
 99  
100      @property
101      def auto_write(self):
102          """Auto write updates to the display."""
103          return self._auto_write
104  
105      @auto_write.setter
106      def auto_write(self, auto_write):
107          if isinstance(auto_write, bool):
108              self._auto_write = auto_write
109          else:
110              raise ValueError("Must set to either True or False.")
111  
112      def show(self):
113          """Refresh the display and show the changes."""
114          with self.i2c_device:
115              # Byte 0 is 0x00, address of LED data register. The remaining 16
116              # bytes are the display register data to set.
117              self.i2c_device.write(self._buffer)
118  
119      def fill(self, color):
120          """Fill the whole display with the given color."""
121          fill = 0xFF if color else 0x00
122          for i in range(16):
123              self._buffer[i + 1] = fill
124          if self._auto_write:
125              self.show()
126  
127      def _pixel(self, x, y, color=None):
128          addr = 2 * y + x // 8
129          mask = 1 << x % 8
130          if color is None:
131              return bool(self._buffer[addr + 1] & mask)
132          if color:
133              # set the bit
134              self._buffer[addr + 1] |= mask
135          else:
136              # clear the bit
137              self._buffer[addr + 1] &= ~mask
138          if self._auto_write:
139              self.show()
140          return None
141  
142      def _set_buffer(self, i, value):
143          self._buffer[i + 1] = value  # Offset by 1 to move past register address.
144  
145      def _get_buffer(self, i):
146          return self._buffer[i + 1]  # Offset by 1 to move past register address.