/ adafruit_trellism4.py
adafruit_trellism4.py
1 # The MIT License (MIT) 2 # 3 # Copyright (c) 2018 Scott Shawcroft 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 13 # all 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 21 # THE SOFTWARE. 22 """ 23 `adafruit_trellism4` 24 ==================================================== 25 26 CircuitPython library for the Trellis M4 Express. 27 28 * Author(s): Scott Shawcroft, Kattni Rembor 29 30 Implementation Notes 31 -------------------- 32 33 **Hardware:** 34 35 # Add link to Trellis M4 Express when product is released. 36 37 **Software and Dependencies:** 38 39 * Adafruit CircuitPython firmware for the supported boards: 40 https://github.com/adafruit/circuitpython/releases 41 42 43 """ 44 45 import board 46 import digitalio 47 import neopixel 48 import adafruit_matrixkeypad 49 50 __version__ = "0.0.0-auto.0" 51 __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_TrellisM4.git" 52 53 54 class _NeoPixelArray: 55 """Creates a NeoPixel array for use in the ``TrellisM4Express`` class.""" 56 57 def __init__(self, pin, *, width, height, rotation=0): 58 self._neopixel = neopixel.NeoPixel(pin, width * height, auto_write=True) 59 if rotation % 90 != 0: 60 raise ValueError("Only 90 degree rotations supported") 61 self._rotation = rotation % 360 62 if self._rotation in (90, 270): 63 width, height = height, width 64 self._width = width 65 self._height = height 66 67 def __setitem__(self, index, value): 68 if not isinstance(index, tuple) or len(index) != 2: 69 raise IndexError("Index must be tuple") 70 if index[0] >= self.width or index[1] >= self.height: 71 raise IndexError("Pixel assignment outside available coordinates.") 72 73 offset = self._calculate_pixel_offset(index) 74 75 self._neopixel[offset] = value 76 77 def __getitem__(self, index): 78 if not isinstance(index, tuple) or len(index) != 2: 79 raise IndexError("Index must be tuple") 80 if index[0] >= self.width or index[1] >= self.height: 81 raise IndexError("Pixel outside available coordinates.") 82 83 offset = self._calculate_pixel_offset(index) 84 85 return self._neopixel[offset] 86 87 def _calculate_pixel_offset(self, index): 88 if self._rotation == 0 or self._rotation == 180: 89 offset = self.width * index[1] + index[0] 90 if self._rotation == 180: 91 offset = self.width * self.height - offset - 1 92 elif self._rotation == 270: 93 offset = self.height * index[0] + (self.height - index[1] - 1) 94 elif self._rotation == 90: 95 offset = self.height * (self.width - index[0] - 1) + index[1] 96 97 if offset < 0: 98 raise IndexError("Pixel outside available coordinates.") 99 100 return offset 101 102 def show(self): 103 """ 104 Shows the new colors on the pixels themselves if they haven't already 105 been autowritten. 106 107 Use when ``auto_write`` is set to ``False``. 108 109 The colors may or may not be showing after this function returns because 110 it may be done asynchronously. 111 """ 112 self._neopixel.show() 113 114 @property 115 def auto_write(self): 116 """ 117 True if the neopixels should immediately change when set. If False, 118 ``show`` must be called explicitly. 119 120 This example disables ``auto_write``, sets every pixel, calls ``show()``, then 121 re-enables ``auto-write``. 122 123 .. code-block:: python 124 125 import adafruit_trellism4 126 127 trellis = adafruit_trellism4.TrellisM4Express() 128 129 trellis.pixels.auto_write = False 130 131 for x in range(trellis.pixels.width): 132 for y in range(trellis.pixels.height): 133 trellis.pixels[x, y] = (0, 255, 0) 134 135 trellis.pixels.show() # must call show() when auto_write == False 136 137 trellis.pixels.auto_write = True 138 """ 139 return self._neopixel.auto_write 140 141 @auto_write.setter 142 def auto_write(self, val): 143 self._neopixel.auto_write = val 144 145 @property 146 def brightness(self): 147 """ 148 The overall brightness of the pixel. Must be a number between 0 and 149 1, where the number represents a percentage between 0 and 100, i.e. ``0.3`` is 30%. 150 151 This example sets the brightness to ``0.3`` and turns all the LEDs red: 152 153 .. code-block:: python 154 155 import adafruit_trellism4 156 157 trellis = adafruit_trellism4.TrellisM4Express() 158 159 trellis.pixels.brightness = 0.3 160 161 trellis.pixels.fill((255, 0, 0)) 162 """ 163 return self._neopixel.brightness 164 165 @brightness.setter 166 def brightness(self, brightness): 167 self._neopixel.brightness = brightness 168 169 def fill(self, color): 170 """ 171 Colors all the pixels a given color. 172 173 :param color: An (R, G, B) color tuple (such as (255, 0, 0) for red), or a hex color value 174 (such as 0xff0000 for red). 175 176 .. code-block:: python 177 178 import adafruit_trellism4 179 180 trellis = adafruit_trellism4.TrellisM4Express() 181 182 trellis.pixels.fill((255, 0, 0)) 183 184 """ 185 self._neopixel.fill(color) 186 187 @property 188 def width(self): 189 """ 190 The width of the grid. When ``rotation`` is 0, ``width`` is 8. 191 192 .. code-block:: python 193 194 import adafruit_trellism4 195 196 trellis = adafruit_trellism4.TrellisM4Express() 197 198 for x in range(trellis.pixels.width): 199 for y in range(trellis.pixels.height): 200 trellis.pixels[x, y] = (0, 0, 255) 201 """ 202 return self._width 203 204 @property 205 def height(self): 206 """The height of the grid. When ``rotation`` is 0, ``height`` is 4. 207 208 .. code-block:: python 209 210 import adafruit_trellism4 211 212 trellis = adafruit_trellism4.TrellisM4Express() 213 214 for x in range(trellis.pixels.width): 215 for y in range(trellis.pixels.height): 216 trellis.pixels[x, y] = (0, 0, 255) 217 """ 218 return self._height 219 220 221 class TrellisM4Express: 222 """ 223 Represents a single Trellis M4 Express. Do not use more than one at a time. 224 225 :param rotation: Allows for rotating the Trellis M4 Express in 90 degree increments to different 226 positions and utilising the grid from that position. Supports ``0``, ``90``, 227 ``180``, and ``270``. ``0`` degrees is when the USB facing away from you. 228 Default is 0. 229 230 .. code-block:: python 231 232 import time 233 import adafruit_trellism4 234 235 trellis = adafruit_trellism4.TrellisM4Express() 236 237 current_press = set() 238 while True: 239 pressed = set(trellis.pressed_keys) 240 for press in pressed - current_press: 241 print("Pressed:", press) 242 for release in current_press - pressed: 243 print("Released:", release) 244 time.sleep(0.08) 245 current_press = pressed 246 """ 247 248 def __init__(self, rotation=0): 249 self._rotation = rotation 250 251 # Define NeoPixels 252 self.pixels = _NeoPixelArray( 253 board.NEOPIXEL, width=8, height=4, rotation=rotation 254 ) 255 """Sequence like object representing the 32 NeoPixels on the Trellis M4 Express, Provides a 256 two dimensional representation of the NeoPixel grid. 257 258 This example lights up the first pixel green: 259 260 .. code-block:: python 261 262 import adafruit_trellism4 263 264 trellis = adafruit_trellism4.TrellisM4Express() 265 266 trellis.pixels[0, 0] = (0, 255, 0) 267 268 **Options for** ``pixels``: 269 270 ``pixels.fill``: Colors all the pixels a given color. Provide an (R, G, B) color tuple 271 (such as (255, 0, 0) for red), or a hex color value (such as 0xff0000 for red). 272 273 This example colors all pixels red: 274 275 .. code-block:: python 276 277 import adafruit_trellism4 278 279 trellis = adafruit_trellism4.TrellisM4Express() 280 281 trellis.pixels.fill((255, 0, 0)) 282 283 ``pixels.width`` and ``pixels.height``: The width and height of the grid. When ``rotation`` 284 is 0, ``width`` is 8 and ``height`` is 4. 285 286 This example colors all pixels blue: 287 288 .. code-block:: python 289 290 import adafruit_trellism4 291 292 trellis = adafruit_trellism4.TrellisM4Express() 293 294 for x in range(trellis.pixels.width): 295 for y in range(trellis.pixels.height): 296 trellis.pixels[x, y] = (0, 0, 255) 297 298 ``pixels.brightness``: The overall brightness of the pixel. Must be a number between 0 and 299 1, where the number represents a percentage between 0 and 100, i.e. ``0.3`` is 30%. 300 301 This example sets the brightness to ``0.3`` and turns all the LEDs red: 302 303 .. code-block:: python 304 305 import adafruit_trellism4 306 307 trellis = adafruit_trellism4.TrellisM4Express() 308 309 trellis.pixels.brightness = 0.3 310 311 trellis.pixels.fill((255, 0, 0)) 312 """ 313 314 cols = [] 315 for x in range(8): 316 col = digitalio.DigitalInOut(getattr(board, "COL{}".format(x))) 317 cols.append(col) 318 319 rows = [] 320 for y in range(4): 321 row = digitalio.DigitalInOut(getattr(board, "ROW{}".format(y))) 322 rows.append(row) 323 324 key_names = [] 325 for y in range(8): 326 row = [] 327 for x in range(4): 328 if rotation == 0: 329 coord = (y, x) 330 elif rotation == 180: 331 coord = (7 - y, 3 - x) 332 elif rotation == 90: 333 coord = (3 - x, y) 334 elif rotation == 270: 335 coord = (x, 7 - y) 336 row.append(coord) 337 key_names.append(row) 338 339 self._matrix = adafruit_matrixkeypad.Matrix_Keypad(cols, rows, key_names) 340 341 @property 342 def pressed_keys(self): 343 """A list of tuples of currently pressed button coordinates. 344 345 .. code-block:: python 346 347 import time 348 import adafruit_trellism4 349 350 trellis = adafruit_trellism4.TrellisM4Express() 351 352 current_press = set() 353 while True: 354 pressed = set(trellis.pressed_keys) 355 for press in pressed - current_press: 356 print("Pressed:", press) 357 for release in current_press - pressed: 358 print("Released:", release) 359 time.sleep(0.08) 360 current_press = pressed 361 """ 362 return self._matrix.pressed_keys