From b756b5efc6d6948eee3df8f7f0e473b45d0c84c9 Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Fri, 22 Mar 2024 00:04:16 -0400 Subject: [PATCH 01/33] Add Rotation and Typing --- adafruit_is31fl3731/__init__.py | 138 ++++++++++++------ adafruit_is31fl3731/matrix.py | 22 ++- examples/is31fl3731_16x9_charlieplexed_pwm.py | 49 +++++++ 3 files changed, 161 insertions(+), 48 deletions(-) create mode 100644 examples/is31fl3731_16x9_charlieplexed_pwm.py diff --git a/adafruit_is31fl3731/__init__.py b/adafruit_is31fl3731/__init__.py index 49290a4..bece7b9 100644 --- a/adafruit_is31fl3731/__init__.py +++ b/adafruit_is31fl3731/__init__.py @@ -55,6 +55,15 @@ from adafruit_bus_device.i2c_device import I2CDevice +try: + from typing import TYPE_CHECKING, List, Tuple + + if TYPE_CHECKING: + from circuitpython_typing import ReadableBuffer + import busio +except ImportError as e: + pass + __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_IS31FL3731.git" @@ -89,17 +98,18 @@ class IS31FL3731: :param ~busio.I2C i2c: the connected i2c bus i2c_device :param int address: the device address; defaults to 0x74 + :param int frames: static 0 or animation frames (0-7) """ - width = 16 - height = 9 + width: int = 16 + height: int = 9 - def __init__(self, i2c, address=0x74, frames=None): + def __init__(self, i2c: busio.I2C, address: int = 0x74, frames: int = None) -> None: self.i2c_device = I2CDevice(i2c, address) self._frame = None self._init(frames=frames) - def _i2c_read_reg(self, reg, result): + def _i2c_read_reg(self, reg: int = None, result: bytes = None) -> bytes: # Read a buffer of data from the specified 8-bit I2C register address. # The provided result parameter will be filled to capacity with bytes # of data read from the register. @@ -108,36 +118,40 @@ def _i2c_read_reg(self, reg, result): return result return None - def _i2c_write_reg(self, reg, data): + def _i2c_write_reg(self, reg: int = None, data: bytes = None) -> bytes: # Write a contiguous block of data (bytearray) starting at the # specified I2C register address (register passed as argument). self._i2c_write_block(bytes([reg]) + data) - def _i2c_write_block(self, data): + def _i2c_write_block(self, data: bytes = None) -> bytes: # Write a buffer of data (byte array) to the specified I2C register # address. with self.i2c_device as i2c: i2c.write(data) - def _bank(self, bank=None): + def _bank(self, bank: int = None) -> int: if bank is None: result = bytearray(1) return self._i2c_read_reg(_BANK_ADDRESS, result)[0] self._i2c_write_reg(_BANK_ADDRESS, bytearray([bank])) return None - def _register(self, bank, register, value=None): + def _register( + self, bank: int = None, register: int = None, value: int = None + ) -> int: self._bank(bank) if value is None: result = bytearray(1) + print(f"Register: {result}") return self._i2c_read_reg(register, result)[0] self._i2c_write_reg(register, bytearray([value])) return None def _mode(self, mode=None): + """Function for setting _register mode""" return self._register(_CONFIG_BANK, _MODE_REGISTER, mode) - def _init(self, frames=None): + def _init(self, frames: int = 0) -> int: self.sleep(True) # Clear config; sets to Picture Mode, no audio sync, maintains sleep self._bank(_CONFIG_BANK) @@ -160,7 +174,7 @@ def reset(self): time.sleep(0.01) # 10 MS pause to reset. self.sleep(False) - def sleep(self, value): + def sleep(self, value: bool = False): """ Set the Software Shutdown Register bit @@ -168,7 +182,7 @@ def sleep(self, value): """ return self._register(_CONFIG_BANK, _SHUTDOWN_REGISTER, not value) - def autoplay(self, delay=0, loops=0, frames=0): + def autoplay(self, delay: float = 0.0, loops: int = 0, frames: int = 0) -> int: """ Start autoplay @@ -190,15 +204,15 @@ def autoplay(self, delay=0, loops=0, frames=0): self._register(_CONFIG_BANK, _AUTOPLAY2_REGISTER, delay % 64) self._mode(_AUTOPLAY_MODE | self._frame) - def fade(self, fade_in=None, fade_out=None, pause=0): + def fade(self, fade_in: int = None, fade_out: int = None, pause: int = 0) -> int: """ Start and stop the fade feature. If both fade_in and fade_out are None (the default), the breath feature is used for fading. if fade_in is None, then fade_in = fade_out. If fade_out is None, then fade_out = fade_in - :param fade_in: positive number; 0->100 - :param fade-out: positive number; 0->100 - :param pause: breath register 2 pause value + :param fade_in: int positive number; 0->100 + :param fade-out: int positive number; 0->100 + :param pause: int breath register 2 pause value """ if fade_in is None and fade_out is None: self._register(_CONFIG_BANK, _BREATH2_REGISTER, 0) @@ -223,12 +237,12 @@ def fade(self, fade_in=None, fade_out=None, pause=0): self._register(_CONFIG_BANK, _BREATH1_REGISTER, fade_out << 4 | fade_in) self._register(_CONFIG_BANK, _BREATH2_REGISTER, 1 << 4 | pause) - def frame(self, frame=None, show=True): + def frame(self, frame: int = None, show: bool = True) -> int: """ Set the current frame - :param frame: frame number; 0-7 or None. If None function returns current frame - :param show: True to show the frame; False to not show. + :param frame: int frame number; 0-7 or None. If None function returns current frame + :param show: bool True to show the frame; False to not show. """ if frame is None: return self._frame @@ -239,11 +253,17 @@ def frame(self, frame=None, show=True): self._register(_CONFIG_BANK, _FRAME_REGISTER, frame) return None - def audio_sync(self, value=None): + def audio_sync(self, value: int = None) -> int: """Set the audio sync feature register""" return self._register(_CONFIG_BANK, _AUDIOSYNC_REGISTER, value) - def audio_play(self, sample_rate, audio_gain=0, agc_enable=False, agc_fast=False): + def audio_play( + self, + sample_rate: int = 0, + audio_gain: int = 0, + agc_enable: bool = False, + agc_fast: bool = False, + ) -> int: """Controls the audio play feature""" if sample_rate == 0: self._mode(_PICTURE_MODE) @@ -262,7 +282,7 @@ def audio_play(self, sample_rate, audio_gain=0, agc_enable=False, agc_fast=False ) self._mode(_AUDIOPLAY_MODE) - def blink(self, rate=None): + def blink(self, rate: int = None) -> int: """Updates the blink register""" # pylint: disable=no-else-return # This needs to be refactored when it can be tested @@ -275,13 +295,13 @@ def blink(self, rate=None): self._register(_CONFIG_BANK, _BLINK_REGISTER, rate & 0x07 | 0x08) return None - def fill(self, color=None, blink=None, frame=None): + def fill(self, color: int = None, blink: bool = False, frame: int = 0) -> int: """ Fill the display with a brightness level :param color: brightness 0->255 - :param blink: True if blinking is required - :param frame: which frame to fill 0->7 + :param blink: bool True to blink + :param frame: int the frame to set the pixel, default 0 """ if frame is None: frame = self._frame @@ -306,30 +326,66 @@ def pixel_addr(x, y): return x + y * 16 # pylint: disable-msg=too-many-arguments - def pixel(self, x, y, color=None, blink=None, frame=None): + def pixel( + self, + x: int, + y: int, + color: int = 255, + blink: bool = False, + frame: int = 0, + rotate: int = 0, + ): """ - Blink or brightness for x-, y-pixel - - :param x: horizontal pixel position - :param y: vertical pixel position - :param color: brightness value 0->255 - :param blink: True to blink - :param frame: the frame to set the pixel + Matrix display configuration + + :param x: int horizontal pixel position + :param y: int vertical pixel position + :param color: int brightness value 0->255 + :param blink: bool True to blink + :param frame: int the frame to set the pixel, default 0 + :param rotate: int display rotation (0, 90, 180, 270) """ - if not 0 <= x <= self.width: - return None - if not 0 <= y <= self.height: - return None - pixel = self.pixel_addr(x, y) + + if rotate not in (0, 90, 180, 270): + raise ValueError("Rotation must be 0, 90, 180, or 270 degrees") + + if rotate == 0: + if not 0 <= x <= self.width: + return None + if not 0 <= y <= self.height: + return None + pixel = self.pixel_addr(x, y) + elif rotate == 90: + if not 0 <= y <= self.width: + return None + if not 0 <= x <= self.height: + return None + pixel = self.pixel_addr(y, self.height - x - 1) + elif rotate == 180: + if not 0 <= x <= self.width: + return None + if not 0 <= y <= self.height: + return None + pixel = self.pixel_addr(self.width - x - 1, self.height - y - 1) + elif rotate == 270: + if not 0 <= y <= self.width: + return None + if not 0 <= x <= self.height: + return None + pixel = self.pixel_addr(self.width - y - 1, x) + if color is None and blink is None: return self._register(self._frame, pixel) + # frames other than 0 only used in animation. allow None. if frame is None: frame = self._frame + # Brightness if color is not None: if not 0 <= color <= 255: - raise ValueError("Color out of range") + raise ValueError("Brightness or Color out of range (0-255)") self._register(frame, _COLOR_OFFSET + pixel, color) - if blink is not None: + # Blink works but not well while animated + if blink: addr, bit = divmod(pixel, 8) bits = self._register(frame, _BLINK_OFFSET + addr) if blink: @@ -341,13 +397,13 @@ def pixel(self, x, y, color=None, blink=None, frame=None): # pylint: enable-msg=too-many-arguments - def image(self, img, blink=None, frame=None): + def image(self, img: bytes = None, blink: bool = False, frame: int = 0) -> bytes: """Set buffer to value of Python Imaging Library image. The image should be in 8-bit mode (L) and a size equal to the display size. :param img: Python Imaging Library image :param blink: True to blink - :param frame: the frame to set the image + :param frame: the frame to set the image, default 0 """ if img.mode != "L": raise ValueError("Image must be in mode L.") diff --git a/adafruit_is31fl3731/matrix.py b/adafruit_is31fl3731/matrix.py index 93b3034..22da603 100644 --- a/adafruit_is31fl3731/matrix.py +++ b/adafruit_is31fl3731/matrix.py @@ -29,15 +29,23 @@ # imports from . import IS31FL3731 +try: + from typing import TYPE_CHECKING, List, Tuple + + if TYPE_CHECKING: + from circuitpython_typing import ReadableBuffer +except ImportError as e: + pass + class Matrix(IS31FL3731): - """Supports the Charlieplexed feather wing""" + """Charlieplexed Featherwing & IS31FL3731 I2C Modules""" - width = 16 - height = 9 + width: int = 16 + height: int = 9 @staticmethod - def pixel_addr(x, y): + def pixel_addr(x: int, y: int) -> int: """Calulate the offset into the device array for x,y pixel""" return x + y * 16 @@ -48,7 +56,7 @@ def pixel_addr(x, y): # for animation. Buffering the full matrix for a quick write is not a # memory concern here, as by definition this method is used with PIL # images; we're not running on a RAM-constrained microcontroller. - def image(self, img, blink=None, frame=None): + def image(self, img: str = None, blink: bool = False, frame: int = 0): """Set buffer to value of Python Imaging Library image. The image should be in 8-bit mode (L) and a size equal to the display size. @@ -67,13 +75,13 @@ def image(self, img, blink=None, frame=None): ) # Frame-select and then write pixel data in one big operation - if frame is not None: + if frame is not 0: self._bank(frame) # We can safely reduce the image to a "flat" byte sequence because # the matrix layout is known linear; no need to go through a 2D # pixel array or invoke pixel_addr(). self._i2c_write_block(bytes([0x24]) + img.tobytes()) # Set or clear blink state if requested, for all pixels at once - if blink is not None: + if blink: # 0x12 is _BLINK_OFFSET in __init__.py self._i2c_write_block(bytes([0x12] + [1 if blink else 0] * 18)) diff --git a/examples/is31fl3731_16x9_charlieplexed_pwm.py b/examples/is31fl3731_16x9_charlieplexed_pwm.py new file mode 100644 index 0000000..8c5bed6 --- /dev/null +++ b/examples/is31fl3731_16x9_charlieplexed_pwm.py @@ -0,0 +1,49 @@ +# SPDX-FileCopyrightText: 2024 DJDevon3 +# SPDX-License-Identifier: MIT +""" Adafruit 16x9 Charlieplexed PWM LED Matrix Example """ + +import board +import adafruit_framebuf + +from adafruit_is31fl3731.matrix import Matrix as Display + +# Uncomment for Pi Pico +# import busio +# i2c = busio.I2C(board.GP21, board.GP20) + +i2c = board.STEMMA_I2C() +display = Display(i2c, address=0x74) + +pixel_rotation = 90 # display rotation (0,90,180,270) +pixel_brightness = 20 # values (0-255) +pixel_blink = False # blink entire display + +text_to_show = "Hello World!" # Scrolling marquee text + +print(f"Display Dimensions: {display.width}x{display.height}") +print(f"Text: {text_to_show}") + +# Create a framebuffer for our display +buf = bytearray(32) # 2 bytes tall x 16 wide = 32 bytes (9 bits is 2 bytes) +buffer = adafruit_framebuf.FrameBuffer( + buf, display.width, display.height, adafruit_framebuf.MVLSB +) + +frame = 0 # start with frame 0 +while True: + # Looping marquee + for i in range(len(text_to_show) * 9): + buffer.fill(0) + buffer.text(text_to_show, -i + display.width, 0, color=1) + display.frame(frame, show=False) + display.fill(0) + for x in range(display.width): + # using the FrameBuffer text result + bite = buf[x] + for y in range(display.height): + bit = 1 << y & bite + # if bit > 0 then set the pixel brightness + if bit: + display.pixel( + x, y, pixel_brightness, blink=pixel_blink, rotate=pixel_rotation + ) From 3232d2837aae268a3179b4741e6eb18578ae39cf Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Fri, 22 Mar 2024 00:52:22 -0400 Subject: [PATCH 02/33] Cleaning up pylint errors --- adafruit_is31fl3731/__init__.py | 32 +++++++++---------- adafruit_is31fl3731/matrix.py | 8 ++--- examples/is31fl3731_16x9_charlieplexed_pwm.py | 22 ++++++------- 3 files changed, 29 insertions(+), 33 deletions(-) diff --git a/adafruit_is31fl3731/__init__.py b/adafruit_is31fl3731/__init__.py index bece7b9..9f1f9dc 100644 --- a/adafruit_is31fl3731/__init__.py +++ b/adafruit_is31fl3731/__init__.py @@ -104,7 +104,7 @@ class IS31FL3731: width: int = 16 height: int = 9 - def __init__(self, i2c: busio.I2C, address: int = 0x74, frames: int = None) -> None: + def __init__(self, i2c: None, address: int = 0x74, frames: int = None) -> None: self.i2c_device = I2CDevice(i2c, address) self._frame = None self._init(frames=frames) @@ -325,7 +325,7 @@ def pixel_addr(x, y): """Calulate the offset into the device array for x,y pixel""" return x + y * 16 - # pylint: disable-msg=too-many-arguments + # pylint: disable-msg=too-many-arguments, too-many-branches def pixel( self, x: int, @@ -350,27 +350,27 @@ def pixel( raise ValueError("Rotation must be 0, 90, 180, or 270 degrees") if rotate == 0: - if not 0 <= x <= self.width: - return None - if not 0 <= y <= self.height: + check_x = 0 <= x <= self.width + check_y = 0 <= y <= self.height + if not (check_x and check_y): return None pixel = self.pixel_addr(x, y) elif rotate == 90: - if not 0 <= y <= self.width: - return None - if not 0 <= x <= self.height: + check_x = 0 <= y <= self.width + check_y = 0 <= x <= self.height + if not (check_x and check_y): return None pixel = self.pixel_addr(y, self.height - x - 1) elif rotate == 180: - if not 0 <= x <= self.width: - return None - if not 0 <= y <= self.height: + check_x = 0 <= x <= self.width + check_y = 0 <= y <= self.height + if not (check_x and check_y): return None pixel = self.pixel_addr(self.width - x - 1, self.height - y - 1) elif rotate == 270: - if not 0 <= y <= self.width: - return None - if not 0 <= x <= self.height: + check_x = 0 <= y <= self.width + check_y = 0 <= x <= self.height + if not (check_x and check_y): return None pixel = self.pixel_addr(self.width - y - 1, x) @@ -410,9 +410,7 @@ def image(self, img: bytes = None, blink: bool = False, frame: int = 0) -> bytes imwidth, imheight = img.size if imwidth != self.width or imheight != self.height: raise ValueError( - "Image must be same dimensions as display ({0}x{1}).".format( - self.width, self.height - ) + f"Image must be same dimensions as display {self.width}x{self.height}" ) # Grab all the pixels from the image, faster than getpixel. pixels = img.load() diff --git a/adafruit_is31fl3731/matrix.py b/adafruit_is31fl3731/matrix.py index 22da603..acedfe3 100644 --- a/adafruit_is31fl3731/matrix.py +++ b/adafruit_is31fl3731/matrix.py @@ -30,7 +30,7 @@ from . import IS31FL3731 try: - from typing import TYPE_CHECKING, List, Tuple + from typing import TYPE_CHECKING if TYPE_CHECKING: from circuitpython_typing import ReadableBuffer @@ -69,13 +69,11 @@ def image(self, img: str = None, blink: bool = False, frame: int = 0): raise ValueError("Image must be in mode L.") if img.size[0] != self.width or img.size[1] != self.height: raise ValueError( - "Image must be same dimensions as display ({0}x{1}).".format( - self.width, self.height - ) + f"Image must be same dimensions as display {self.width}x{self.height}" ) # Frame-select and then write pixel data in one big operation - if frame is not 0: + if frame != 0: self._bank(frame) # We can safely reduce the image to a "flat" byte sequence because # the matrix layout is known linear; no need to go through a 2D diff --git a/examples/is31fl3731_16x9_charlieplexed_pwm.py b/examples/is31fl3731_16x9_charlieplexed_pwm.py index 8c5bed6..6c2878e 100644 --- a/examples/is31fl3731_16x9_charlieplexed_pwm.py +++ b/examples/is31fl3731_16x9_charlieplexed_pwm.py @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: 2024 DJDevon3 # SPDX-License-Identifier: MIT """ Adafruit 16x9 Charlieplexed PWM LED Matrix Example """ - +# pylint: disable=import-error import board import adafruit_framebuf @@ -14,14 +14,14 @@ i2c = board.STEMMA_I2C() display = Display(i2c, address=0x74) -pixel_rotation = 90 # display rotation (0,90,180,270) -pixel_brightness = 20 # values (0-255) -pixel_blink = False # blink entire display +PIXEL_ROTATION = 0 # display rotation (0,90,180,270) +PIXEL_BRIGHTNESS = 20 # values (0-255) +PIXEL_BLINK = False # blink entire display -text_to_show = "Hello World!" # Scrolling marquee text +TEXT = "Hello World!" # Scrolling marquee text print(f"Display Dimensions: {display.width}x{display.height}") -print(f"Text: {text_to_show}") +print(f"Text: {TEXT}") # Create a framebuffer for our display buf = bytearray(32) # 2 bytes tall x 16 wide = 32 bytes (9 bits is 2 bytes) @@ -29,13 +29,13 @@ buf, display.width, display.height, adafruit_framebuf.MVLSB ) -frame = 0 # start with frame 0 +FRAME = 0 # start with frame 0 while True: # Looping marquee - for i in range(len(text_to_show) * 9): + for i in range(len(TEXT) * 9): buffer.fill(0) - buffer.text(text_to_show, -i + display.width, 0, color=1) - display.frame(frame, show=False) + buffer.text(TEXT, -i + display.width, 0, color=1) + display.frame(FRAME, show=False) display.fill(0) for x in range(display.width): # using the FrameBuffer text result @@ -45,5 +45,5 @@ # if bit > 0 then set the pixel brightness if bit: display.pixel( - x, y, pixel_brightness, blink=pixel_blink, rotate=pixel_rotation + x, y, PIXEL_BRIGHTNESS, blink=PIXEL_BLINK, rotate=PIXEL_ROTATION ) From 35b4ac833f13f9c28336dfe5533e16efc3529255 Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Tue, 2 Apr 2024 06:53:07 -0400 Subject: [PATCH 03/33] Attempt #2 also ran black formatter I'm pretty sure I won't even get it on my 2nd attempt so might as well number them. --- adafruit_is31fl3731/__init__.py | 80 ++++++++++++++++++++++----------- adafruit_is31fl3731/matrix.py | 4 +- 2 files changed, 56 insertions(+), 28 deletions(-) diff --git a/adafruit_is31fl3731/__init__.py b/adafruit_is31fl3731/__init__.py index 9f1f9dc..874ad44 100644 --- a/adafruit_is31fl3731/__init__.py +++ b/adafruit_is31fl3731/__init__.py @@ -104,12 +104,19 @@ class IS31FL3731: width: int = 16 height: int = 9 - def __init__(self, i2c: None, address: int = 0x74, frames: int = None) -> None: + def __init__( + self, + i2c: busio.I2C, + frames: Optional[int] = None, + address: int = 0x74, + ): self.i2c_device = I2CDevice(i2c, address) self._frame = None self._init(frames=frames) - def _i2c_read_reg(self, reg: int = None, result: bytes = None) -> bytes: + def _i2c_read_reg( + self, reg: Optional[int] = None, result: Optional[ReadableBuffer] = None + ) -> Optional[ReadableBuffer]: # Read a buffer of data from the specified 8-bit I2C register address. # The provided result parameter will be filled to capacity with bytes # of data read from the register. @@ -118,18 +125,20 @@ def _i2c_read_reg(self, reg: int = None, result: bytes = None) -> bytes: return result return None - def _i2c_write_reg(self, reg: int = None, data: bytes = None) -> bytes: + def _i2c_write_reg( + self, reg: Optional[int] = None, data: Optional[ReadableBuffer] = None + ) -> None: # Write a contiguous block of data (bytearray) starting at the # specified I2C register address (register passed as argument). self._i2c_write_block(bytes([reg]) + data) - def _i2c_write_block(self, data: bytes = None) -> bytes: + def _i2c_write_block(self, data: Optional[ReadableBuffer]) -> None: # Write a buffer of data (byte array) to the specified I2C register # address. with self.i2c_device as i2c: i2c.write(data) - def _bank(self, bank: int = None) -> int: + def _bank(self, bank: Optional[int] = None) -> Optional[int]: if bank is None: result = bytearray(1) return self._i2c_read_reg(_BANK_ADDRESS, result)[0] @@ -137,21 +146,23 @@ def _bank(self, bank: int = None) -> int: return None def _register( - self, bank: int = None, register: int = None, value: int = None - ) -> int: + self, + bank: Optional[int] = None, + register: Optional[int] = None, + value: Optional[int] = None, + ) -> Optional[int]: self._bank(bank) if value is None: result = bytearray(1) - print(f"Register: {result}") return self._i2c_read_reg(register, result)[0] self._i2c_write_reg(register, bytearray([value])) return None - def _mode(self, mode=None): + def _mode(self, mode: Optional[int] = None) -> int: """Function for setting _register mode""" return self._register(_CONFIG_BANK, _MODE_REGISTER, mode) - def _init(self, frames: int = 0) -> int: + def _init(self, frames: Iterable) -> None: self.sleep(True) # Clear config; sets to Picture Mode, no audio sync, maintains sleep self._bank(_CONFIG_BANK) @@ -174,7 +185,7 @@ def reset(self): time.sleep(0.01) # 10 MS pause to reset. self.sleep(False) - def sleep(self, value: bool = False): + def sleep(self, value): """ Set the Software Shutdown Register bit @@ -182,7 +193,12 @@ def sleep(self, value: bool = False): """ return self._register(_CONFIG_BANK, _SHUTDOWN_REGISTER, not value) - def autoplay(self, delay: float = 0.0, loops: int = 0, frames: int = 0) -> int: + def autoplay( + self, + delay: Optional[int] = None, + loops: Optional[Iterable] = None, + frames: Optional[int] = None, + ) -> int: """ Start autoplay @@ -204,7 +220,12 @@ def autoplay(self, delay: float = 0.0, loops: int = 0, frames: int = 0) -> int: self._register(_CONFIG_BANK, _AUTOPLAY2_REGISTER, delay % 64) self._mode(_AUTOPLAY_MODE | self._frame) - def fade(self, fade_in: int = None, fade_out: int = None, pause: int = 0) -> int: + def fade( + self, + fade_in: Optional[int] = None, + fade_out: Optional[int] = None, + pause: Optional[int] = None, + ) -> int: """ Start and stop the fade feature. If both fade_in and fade_out are None (the default), the breath feature is used for fading. if fade_in is None, then @@ -237,7 +258,7 @@ def fade(self, fade_in: int = None, fade_out: int = None, pause: int = 0) -> int self._register(_CONFIG_BANK, _BREATH1_REGISTER, fade_out << 4 | fade_in) self._register(_CONFIG_BANK, _BREATH2_REGISTER, 1 << 4 | pause) - def frame(self, frame: int = None, show: bool = True) -> int: + def frame(self, frame: Optional[int] = None, show: bool = True) -> Optional[int]: """ Set the current frame @@ -253,17 +274,17 @@ def frame(self, frame: int = None, show: bool = True) -> int: self._register(_CONFIG_BANK, _FRAME_REGISTER, frame) return None - def audio_sync(self, value: int = None) -> int: + def audio_sync(self, value: Optional[int]) -> Optional[int]: """Set the audio sync feature register""" return self._register(_CONFIG_BANK, _AUDIOSYNC_REGISTER, value) def audio_play( self, - sample_rate: int = 0, + sample_rate: int, audio_gain: int = 0, agc_enable: bool = False, agc_fast: bool = False, - ) -> int: + ) -> None: """Controls the audio play feature""" if sample_rate == 0: self._mode(_PICTURE_MODE) @@ -282,7 +303,7 @@ def audio_play( ) self._mode(_AUDIOPLAY_MODE) - def blink(self, rate: int = None) -> int: + def blink(self, rate: Optional[int]) -> Optional[int]: """Updates the blink register""" # pylint: disable=no-else-return # This needs to be refactored when it can be tested @@ -295,7 +316,12 @@ def blink(self, rate: int = None) -> int: self._register(_CONFIG_BANK, _BLINK_REGISTER, rate & 0x07 | 0x08) return None - def fill(self, color: int = None, blink: bool = False, frame: int = 0) -> int: + def fill( + self, + color: Optional[int] = None, + frame: Optional[int] = None, + blink: bool = False, + ): """ Fill the display with a brightness level @@ -321,20 +347,20 @@ def fill(self, color: int = None, blink: bool = False, frame: int = 0) -> int: # This function must be replaced for each board @staticmethod - def pixel_addr(x, y): + def pixel_addr(x: int, y: int) -> int: """Calulate the offset into the device array for x,y pixel""" return x + y * 16 - # pylint: disable-msg=too-many-arguments, too-many-branches + # pylint: disable-msg=too-many-arguments def pixel( self, x: int, y: int, - color: int = 255, + color: Optional[int] = None, + frame: Optional[int] = None, blink: bool = False, - frame: int = 0, rotate: int = 0, - ): + ) -> Optional[int]: """ Matrix display configuration @@ -397,7 +423,7 @@ def pixel( # pylint: enable-msg=too-many-arguments - def image(self, img: bytes = None, blink: bool = False, frame: int = 0) -> bytes: + def image(self, img: Optional[str], frame: Optional[int], blink: bool = False): """Set buffer to value of Python Imaging Library image. The image should be in 8-bit mode (L) and a size equal to the display size. @@ -410,7 +436,9 @@ def image(self, img: bytes = None, blink: bool = False, frame: int = 0) -> bytes imwidth, imheight = img.size if imwidth != self.width or imheight != self.height: raise ValueError( - f"Image must be same dimensions as display {self.width}x{self.height}" + "Image must be same dimensions as display ({0}x{1}).".format( + self.width, self.height + ) ) # Grab all the pixels from the image, faster than getpixel. pixels = img.load() diff --git a/adafruit_is31fl3731/matrix.py b/adafruit_is31fl3731/matrix.py index acedfe3..c4d79ac 100644 --- a/adafruit_is31fl3731/matrix.py +++ b/adafruit_is31fl3731/matrix.py @@ -56,7 +56,7 @@ def pixel_addr(x: int, y: int) -> int: # for animation. Buffering the full matrix for a quick write is not a # memory concern here, as by definition this method is used with PIL # images; we're not running on a RAM-constrained microcontroller. - def image(self, img: str = None, blink: bool = False, frame: int = 0): + def image(self, img: Optional[Image], frame: Optional[int], blink: bool = False): """Set buffer to value of Python Imaging Library image. The image should be in 8-bit mode (L) and a size equal to the display size. @@ -73,7 +73,7 @@ def image(self, img: str = None, blink: bool = False, frame: int = 0): ) # Frame-select and then write pixel data in one big operation - if frame != 0: + if frame is not None: self._bank(frame) # We can safely reduce the image to a "flat" byte sequence because # the matrix layout is known linear; no need to go through a 2D From 757584ac7c3a7ddba036c108844ecee43af9bc53 Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Tue, 2 Apr 2024 07:30:29 -0400 Subject: [PATCH 04/33] attempt 3 (import Optional) --- adafruit_is31fl3731/__init__.py | 2 +- adafruit_is31fl3731/matrix.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/adafruit_is31fl3731/__init__.py b/adafruit_is31fl3731/__init__.py index 874ad44..2c7e5d5 100644 --- a/adafruit_is31fl3731/__init__.py +++ b/adafruit_is31fl3731/__init__.py @@ -59,7 +59,7 @@ from typing import TYPE_CHECKING, List, Tuple if TYPE_CHECKING: - from circuitpython_typing import ReadableBuffer + from circuitpython_typing import ReadableBuffer, Optional import busio except ImportError as e: pass diff --git a/adafruit_is31fl3731/matrix.py b/adafruit_is31fl3731/matrix.py index c4d79ac..8e02a60 100644 --- a/adafruit_is31fl3731/matrix.py +++ b/adafruit_is31fl3731/matrix.py @@ -33,7 +33,7 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: - from circuitpython_typing import ReadableBuffer + from circuitpython_typing import ReadableBuffer, Optional except ImportError as e: pass From 17d924192a1e57908327ec482ee1c745be6bcdc5 Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Tue, 2 Apr 2024 07:34:18 -0400 Subject: [PATCH 05/33] attempt 4 (import Iterable) Making progress, cutting down the amount of errors. --- adafruit_is31fl3731/__init__.py | 2 +- adafruit_is31fl3731/matrix.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/adafruit_is31fl3731/__init__.py b/adafruit_is31fl3731/__init__.py index 2c7e5d5..a52eb87 100644 --- a/adafruit_is31fl3731/__init__.py +++ b/adafruit_is31fl3731/__init__.py @@ -59,7 +59,7 @@ from typing import TYPE_CHECKING, List, Tuple if TYPE_CHECKING: - from circuitpython_typing import ReadableBuffer, Optional + from circuitpython_typing import ReadableBuffer, Optional, Iterable import busio except ImportError as e: pass diff --git a/adafruit_is31fl3731/matrix.py b/adafruit_is31fl3731/matrix.py index 8e02a60..477e350 100644 --- a/adafruit_is31fl3731/matrix.py +++ b/adafruit_is31fl3731/matrix.py @@ -33,7 +33,7 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: - from circuitpython_typing import ReadableBuffer, Optional + from circuitpython_typing import ReadableBuffer, Optional, Image except ImportError as e: pass From 6d70dd7a6728b6610f752552e1b157f3232d0853 Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Tue, 2 Apr 2024 07:42:26 -0400 Subject: [PATCH 06/33] lets just throw stuff at pylint and see what works... --- adafruit_is31fl3731/__init__.py | 5 +++-- adafruit_is31fl3731/matrix.py | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/adafruit_is31fl3731/__init__.py b/adafruit_is31fl3731/__init__.py index a52eb87..2aef105 100644 --- a/adafruit_is31fl3731/__init__.py +++ b/adafruit_is31fl3731/__init__.py @@ -56,10 +56,11 @@ from adafruit_bus_device.i2c_device import I2CDevice try: - from typing import TYPE_CHECKING, List, Tuple + from typing import TYPE_CHECKING, List, Tuple, Optional, Iterable + from PIL import Image if TYPE_CHECKING: - from circuitpython_typing import ReadableBuffer, Optional, Iterable + from circuitpython_typing import ReadableBuffer import busio except ImportError as e: pass diff --git a/adafruit_is31fl3731/matrix.py b/adafruit_is31fl3731/matrix.py index 477e350..5e5b927 100644 --- a/adafruit_is31fl3731/matrix.py +++ b/adafruit_is31fl3731/matrix.py @@ -30,10 +30,10 @@ from . import IS31FL3731 try: - from typing import TYPE_CHECKING + from typing import TYPE_CHECKING, Optional, Image if TYPE_CHECKING: - from circuitpython_typing import ReadableBuffer, Optional, Image + from circuitpython_typing import ReadableBuffer except ImportError as e: pass From 9f6ab0c444fd74beddb3429d802ee773ef1dde63 Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Tue, 2 Apr 2024 07:49:40 -0400 Subject: [PATCH 07/33] making progress, down to 3 errors. --- adafruit_is31fl3731/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/adafruit_is31fl3731/__init__.py b/adafruit_is31fl3731/__init__.py index 2aef105..2f3fc79 100644 --- a/adafruit_is31fl3731/__init__.py +++ b/adafruit_is31fl3731/__init__.py @@ -47,7 +47,6 @@ https://github.com/adafruit/circuitpython/releases """ - # imports import math import time @@ -55,13 +54,13 @@ from adafruit_bus_device.i2c_device import I2CDevice +import busio try: - from typing import TYPE_CHECKING, List, Tuple, Optional, Iterable + from typing import TYPE_CHECKING, List, Tuple, Optional, Iterable, ReadableBuffer from PIL import Image if TYPE_CHECKING: - from circuitpython_typing import ReadableBuffer - import busio + import circuitpython_typing except ImportError as e: pass @@ -372,6 +371,7 @@ def pixel( :param frame: int the frame to set the pixel, default 0 :param rotate: int display rotation (0, 90, 180, 270) """ + #pylint: disable=too-many-branches if rotate not in (0, 90, 180, 270): raise ValueError("Rotation must be 0, 90, 180, or 270 degrees") From 927c33fcf9e7772ef8176f247c400c795e02cecb Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Tue, 2 Apr 2024 07:51:53 -0400 Subject: [PATCH 08/33] 1 error for black so close! --- adafruit_is31fl3731/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/adafruit_is31fl3731/__init__.py b/adafruit_is31fl3731/__init__.py index 2f3fc79..39e21c4 100644 --- a/adafruit_is31fl3731/__init__.py +++ b/adafruit_is31fl3731/__init__.py @@ -55,6 +55,7 @@ from adafruit_bus_device.i2c_device import I2CDevice import busio + try: from typing import TYPE_CHECKING, List, Tuple, Optional, Iterable, ReadableBuffer from PIL import Image @@ -371,7 +372,7 @@ def pixel( :param frame: int the frame to set the pixel, default 0 :param rotate: int display rotation (0, 90, 180, 270) """ - #pylint: disable=too-many-branches + # pylint: disable=too-many-branches if rotate not in (0, 90, 180, 270): raise ValueError("Rotation must be 0, 90, 180, or 270 degrees") From 2e9d20b21eb3c6c42163cf1a630c213144077a55 Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Tue, 2 Apr 2024 07:56:06 -0400 Subject: [PATCH 09/33] oh come on! fine set it on both imports, see how ya like that pylint. --- adafruit_is31fl3731/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_is31fl3731/__init__.py b/adafruit_is31fl3731/__init__.py index 39e21c4..9fea6c2 100644 --- a/adafruit_is31fl3731/__init__.py +++ b/adafruit_is31fl3731/__init__.py @@ -61,7 +61,7 @@ from PIL import Image if TYPE_CHECKING: - import circuitpython_typing + from circuitpython_typing import ReadableBuffer except ImportError as e: pass From e44eae5635256ce7f302a9929491570f246e1aee Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Tue, 2 Apr 2024 08:13:23 -0400 Subject: [PATCH 10/33] Ran to ChatGPT for help and here's what it says to do. --- adafruit_is31fl3731/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/adafruit_is31fl3731/__init__.py b/adafruit_is31fl3731/__init__.py index 9fea6c2..36cbc49 100644 --- a/adafruit_is31fl3731/__init__.py +++ b/adafruit_is31fl3731/__init__.py @@ -57,7 +57,7 @@ import busio try: - from typing import TYPE_CHECKING, List, Tuple, Optional, Iterable, ReadableBuffer + from typing import TYPE_CHECKING, List, Tuple, Optional, Iterable from PIL import Image if TYPE_CHECKING: @@ -65,6 +65,7 @@ except ImportError as e: pass + __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_IS31FL3731.git" From e406fb9a5e62d72fc23f395dcb13996eddcf9e81 Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Tue, 2 Apr 2024 08:39:47 -0400 Subject: [PATCH 11/33] remove if TYPE_CHECKING, this will probably fail in Blinka , let Melissa figure it out? --- adafruit_is31fl3731/__init__.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/adafruit_is31fl3731/__init__.py b/adafruit_is31fl3731/__init__.py index 36cbc49..2dc48fe 100644 --- a/adafruit_is31fl3731/__init__.py +++ b/adafruit_is31fl3731/__init__.py @@ -59,9 +59,7 @@ try: from typing import TYPE_CHECKING, List, Tuple, Optional, Iterable from PIL import Image - - if TYPE_CHECKING: - from circuitpython_typing import ReadableBuffer + from circuitpython_typing import ReadableBuffer except ImportError as e: pass From d7ff776b05aeb46898c4886d8de23e18966c8b2a Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Tue, 2 Apr 2024 08:45:10 -0400 Subject: [PATCH 12/33] let's see if pylint fails with a class does not exist --- adafruit_is31fl3731/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/adafruit_is31fl3731/__init__.py b/adafruit_is31fl3731/__init__.py index 2dc48fe..bc240c4 100644 --- a/adafruit_is31fl3731/__init__.py +++ b/adafruit_is31fl3731/__init__.py @@ -59,7 +59,9 @@ try: from typing import TYPE_CHECKING, List, Tuple, Optional, Iterable from PIL import Image - from circuitpython_typing import ReadableBuffer + + if TYPE_CHECKING: + from circuitpython_typing import CompletelyMadeUpTest except ImportError as e: pass From a65e2712bc7f0a18d624d85d398bfed2742f4cb8 Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Tue, 2 Apr 2024 08:48:48 -0400 Subject: [PATCH 13/33] this is not fun --- adafruit_is31fl3731/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_is31fl3731/__init__.py b/adafruit_is31fl3731/__init__.py index bc240c4..36cbc49 100644 --- a/adafruit_is31fl3731/__init__.py +++ b/adafruit_is31fl3731/__init__.py @@ -61,7 +61,7 @@ from PIL import Image if TYPE_CHECKING: - from circuitpython_typing import CompletelyMadeUpTest + from circuitpython_typing import ReadableBuffer except ImportError as e: pass From 57f2d1b3b43efebb1038fbd0fa629d6300e88d1f Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Tue, 2 Apr 2024 08:52:38 -0400 Subject: [PATCH 14/33] breaking out the None hammer --- adafruit_is31fl3731/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_is31fl3731/__init__.py b/adafruit_is31fl3731/__init__.py index 36cbc49..8077b9b 100644 --- a/adafruit_is31fl3731/__init__.py +++ b/adafruit_is31fl3731/__init__.py @@ -118,7 +118,7 @@ def __init__( def _i2c_read_reg( self, reg: Optional[int] = None, result: Optional[ReadableBuffer] = None - ) -> Optional[ReadableBuffer]: + ) -> None: # Read a buffer of data from the specified 8-bit I2C register address. # The provided result parameter will be filled to capacity with bytes # of data read from the register. From 4dc90541ff8bf32f748fcf11a6762f2c33360e5f Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Tue, 2 Apr 2024 08:57:26 -0400 Subject: [PATCH 15/33] delete and skip this part? --- adafruit_is31fl3731/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_is31fl3731/__init__.py b/adafruit_is31fl3731/__init__.py index 8077b9b..6185714 100644 --- a/adafruit_is31fl3731/__init__.py +++ b/adafruit_is31fl3731/__init__.py @@ -118,7 +118,7 @@ def __init__( def _i2c_read_reg( self, reg: Optional[int] = None, result: Optional[ReadableBuffer] = None - ) -> None: + ): # Read a buffer of data from the specified 8-bit I2C register address. # The provided result parameter will be filled to capacity with bytes # of data read from the register. From 58d95bd47f661e1066f23a0625dcd64c8eb2e58e Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Tue, 2 Apr 2024 09:03:28 -0400 Subject: [PATCH 16/33] change it to Optional[int], deal with it later. --- adafruit_is31fl3731/__init__.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/adafruit_is31fl3731/__init__.py b/adafruit_is31fl3731/__init__.py index 6185714..2f22d2f 100644 --- a/adafruit_is31fl3731/__init__.py +++ b/adafruit_is31fl3731/__init__.py @@ -116,9 +116,7 @@ def __init__( self._frame = None self._init(frames=frames) - def _i2c_read_reg( - self, reg: Optional[int] = None, result: Optional[ReadableBuffer] = None - ): + def _i2c_read_reg(self, reg: Optional[int] = None, result: Optional[int] = None): # Read a buffer of data from the specified 8-bit I2C register address. # The provided result parameter will be filled to capacity with bytes # of data read from the register. From 4fb28c3a1e2f8dba9b02ceb657cb096aace82ad0 Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Tue, 2 Apr 2024 09:24:11 -0400 Subject: [PATCH 17/33] can has WriteableBuffer? --- adafruit_is31fl3731/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_is31fl3731/__init__.py b/adafruit_is31fl3731/__init__.py index 2f22d2f..f53d957 100644 --- a/adafruit_is31fl3731/__init__.py +++ b/adafruit_is31fl3731/__init__.py @@ -116,7 +116,7 @@ def __init__( self._frame = None self._init(frames=frames) - def _i2c_read_reg(self, reg: Optional[int] = None, result: Optional[int] = None): + def _i2c_read_reg(self, reg: Optional[int] = None, result: Optional[WritableBuffer] = None): # Read a buffer of data from the specified 8-bit I2C register address. # The provided result parameter will be filled to capacity with bytes # of data read from the register. From de5a15c95b6fd87c6c9f48a54101e1eab256fd10 Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Tue, 2 Apr 2024 09:26:01 -0400 Subject: [PATCH 18/33] every...time... black --- adafruit_is31fl3731/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/adafruit_is31fl3731/__init__.py b/adafruit_is31fl3731/__init__.py index f53d957..adf879a 100644 --- a/adafruit_is31fl3731/__init__.py +++ b/adafruit_is31fl3731/__init__.py @@ -61,7 +61,7 @@ from PIL import Image if TYPE_CHECKING: - from circuitpython_typing import ReadableBuffer + from circuitpython_typing import ReadableBuffer, WritableBuffer except ImportError as e: pass @@ -116,7 +116,9 @@ def __init__( self._frame = None self._init(frames=frames) - def _i2c_read_reg(self, reg: Optional[int] = None, result: Optional[WritableBuffer] = None): + def _i2c_read_reg( + self, reg: Optional[int] = None, result: Optional[WritableBuffer] = None + ): # Read a buffer of data from the specified 8-bit I2C register address. # The provided result parameter will be filled to capacity with bytes # of data read from the register. From 5c5f45b5cbccfd4c850a193ec7b5b512a9f632c2 Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Tue, 2 Apr 2024 09:34:28 -0400 Subject: [PATCH 19/33] this is why i can't have nice things --- adafruit_is31fl3731/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_is31fl3731/__init__.py b/adafruit_is31fl3731/__init__.py index adf879a..c984672 100644 --- a/adafruit_is31fl3731/__init__.py +++ b/adafruit_is31fl3731/__init__.py @@ -117,7 +117,7 @@ def __init__( self._init(frames=frames) def _i2c_read_reg( - self, reg: Optional[int] = None, result: Optional[WritableBuffer] = None + self, reg: Optional[int] = None, result: WritableBuffer[bytearray] = None ): # Read a buffer of data from the specified 8-bit I2C register address. # The provided result parameter will be filled to capacity with bytes From 888bd3240ec5ec9ebbe8b0fae16e80d8614004e1 Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Tue, 2 Apr 2024 09:55:56 -0400 Subject: [PATCH 20/33] lets try all the hundreds of different possible syntaxes... --- adafruit_is31fl3731/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adafruit_is31fl3731/__init__.py b/adafruit_is31fl3731/__init__.py index c984672..2aec87d 100644 --- a/adafruit_is31fl3731/__init__.py +++ b/adafruit_is31fl3731/__init__.py @@ -117,8 +117,8 @@ def __init__( self._init(frames=frames) def _i2c_read_reg( - self, reg: Optional[int] = None, result: WritableBuffer[bytearray] = None - ): + self, reg: Optional[int] = None, result: Optional[WritableBuffer] = None + ) -> Optional[WriteableBuffer]: # Read a buffer of data from the specified 8-bit I2C register address. # The provided result parameter will be filled to capacity with bytes # of data read from the register. From 13236c40a72095bf4bb61147162bca8c44a10535 Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Tue, 2 Apr 2024 11:12:14 -0400 Subject: [PATCH 21/33] Using variable before assignment --- adafruit_is31fl3731/__init__.py | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/adafruit_is31fl3731/__init__.py b/adafruit_is31fl3731/__init__.py index 2aec87d..d1b656f 100644 --- a/adafruit_is31fl3731/__init__.py +++ b/adafruit_is31fl3731/__init__.py @@ -61,7 +61,7 @@ from PIL import Image if TYPE_CHECKING: - from circuitpython_typing import ReadableBuffer, WritableBuffer + from circuitpython_typing import ReadableBuffer, WriteableBuffer except ImportError as e: pass @@ -116,9 +116,7 @@ def __init__( self._frame = None self._init(frames=frames) - def _i2c_read_reg( - self, reg: Optional[int] = None, result: Optional[WritableBuffer] = None - ) -> Optional[WriteableBuffer]: + def _i2c_read_reg(self, result: WriteableBuffer, reg: Optional[int] = None) -> None: # Read a buffer of data from the specified 8-bit I2C register address. # The provided result parameter will be filled to capacity with bytes # of data read from the register. @@ -127,14 +125,12 @@ def _i2c_read_reg( return result return None - def _i2c_write_reg( - self, reg: Optional[int] = None, data: Optional[ReadableBuffer] = None - ) -> None: + def _i2c_write_reg(self, data: ReadableBuffer, reg: Optional[int] = None) -> None: # Write a contiguous block of data (bytearray) starting at the # specified I2C register address (register passed as argument). self._i2c_write_block(bytes([reg]) + data) - def _i2c_write_block(self, data: Optional[ReadableBuffer]) -> None: + def _i2c_write_block(self, data: ReadableBuffer) -> None: # Write a buffer of data (byte array) to the specified I2C register # address. with self.i2c_device as i2c: @@ -439,9 +435,7 @@ def image(self, img: Optional[str], frame: Optional[int], blink: bool = False): imwidth, imheight = img.size if imwidth != self.width or imheight != self.height: raise ValueError( - "Image must be same dimensions as display ({0}x{1}).".format( - self.width, self.height - ) + f"Image must be same dimensions as display {self.width}x{self.height}" ) # Grab all the pixels from the image, faster than getpixel. pixels = img.load() From c80cc25ba9d3a73d5370d39c9755f3072b92abd8 Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Tue, 2 Apr 2024 11:22:06 -0400 Subject: [PATCH 22/33] Leroyyyyy Jenkins --- adafruit_is31fl3731/__init__.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/adafruit_is31fl3731/__init__.py b/adafruit_is31fl3731/__init__.py index d1b656f..86e393d 100644 --- a/adafruit_is31fl3731/__init__.py +++ b/adafruit_is31fl3731/__init__.py @@ -59,9 +59,7 @@ try: from typing import TYPE_CHECKING, List, Tuple, Optional, Iterable from PIL import Image - - if TYPE_CHECKING: - from circuitpython_typing import ReadableBuffer, WriteableBuffer + from circuitpython_typing import ReadableBuffer, WriteableBuffer except ImportError as e: pass From 1cbd7c465ac824ed9e10084ea560d220e738c52b Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Tue, 2 Apr 2024 11:25:53 -0400 Subject: [PATCH 23/33] at least i got chicken --- adafruit_is31fl3731/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_is31fl3731/__init__.py b/adafruit_is31fl3731/__init__.py index 86e393d..a569cf6 100644 --- a/adafruit_is31fl3731/__init__.py +++ b/adafruit_is31fl3731/__init__.py @@ -55,11 +55,11 @@ from adafruit_bus_device.i2c_device import I2CDevice import busio +from circuitpython_typing import ReadableBuffer, WriteableBuffer try: from typing import TYPE_CHECKING, List, Tuple, Optional, Iterable from PIL import Image - from circuitpython_typing import ReadableBuffer, WriteableBuffer except ImportError as e: pass From 393aeb8c95e5fee2ff020da7b58e887cf3d1e902 Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Tue, 2 Apr 2024 11:34:38 -0400 Subject: [PATCH 24/33] i'm drowning --- adafruit_is31fl3731/__init__.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/adafruit_is31fl3731/__init__.py b/adafruit_is31fl3731/__init__.py index a569cf6..0dc192d 100644 --- a/adafruit_is31fl3731/__init__.py +++ b/adafruit_is31fl3731/__init__.py @@ -54,12 +54,22 @@ from adafruit_bus_device.i2c_device import I2CDevice -import busio -from circuitpython_typing import ReadableBuffer, WriteableBuffer - try: - from typing import TYPE_CHECKING, List, Tuple, Optional, Iterable + import typing + import busio + from typing import ( + TYPE_CHECKING, + List, + Tuple, + Optional, + Iterable, + ReadableBuffer, + WriteableBuffer, + ) from PIL import Image + + if TYPE_CHECKING: + from circuitpython_typing import ReadableBuffer, WriteableBuffer except ImportError as e: pass From e2b91c244f5215d1f62250f9bb041d05e8754a07 Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Mon, 15 Apr 2024 02:02:52 -0400 Subject: [PATCH 25/33] in my hour of deperation, chatgpt --- adafruit_is31fl3731/__init__.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/adafruit_is31fl3731/__init__.py b/adafruit_is31fl3731/__init__.py index 0dc192d..31539cd 100644 --- a/adafruit_is31fl3731/__init__.py +++ b/adafruit_is31fl3731/__init__.py @@ -57,19 +57,22 @@ try: import typing import busio + from circuitpython_typing import TypeAlias, Union + from circuitpython_typing import ( + WriteableBuffer, + ReadableBuffer, + ) # Import ReadableBuffer here + from typing import ( TYPE_CHECKING, List, Tuple, Optional, Iterable, - ReadableBuffer, - WriteableBuffer, ) + from PIL import Image - if TYPE_CHECKING: - from circuitpython_typing import ReadableBuffer, WriteableBuffer except ImportError as e: pass @@ -124,7 +127,7 @@ def __init__( self._frame = None self._init(frames=frames) - def _i2c_read_reg(self, result: WriteableBuffer, reg: Optional[int] = None) -> None: + def _i2c_read_reg(self, reg: Optional[int] = None, result: Optional[int] = None): # Read a buffer of data from the specified 8-bit I2C register address. # The provided result parameter will be filled to capacity with bytes # of data read from the register. @@ -133,12 +136,14 @@ def _i2c_read_reg(self, result: WriteableBuffer, reg: Optional[int] = None) -> N return result return None - def _i2c_write_reg(self, data: ReadableBuffer, reg: Optional[int] = None) -> None: + def _i2c_write_reg( + self, reg: Optional[int] = None, data: Optional[ReadableBuffer] = None + ) -> None: # Write a contiguous block of data (bytearray) starting at the # specified I2C register address (register passed as argument). self._i2c_write_block(bytes([reg]) + data) - def _i2c_write_block(self, data: ReadableBuffer) -> None: + def _i2c_write_block(self, data: Optional[ReadableBuffer]) -> None: # Write a buffer of data (byte array) to the specified I2C register # address. with self.i2c_device as i2c: @@ -443,7 +448,9 @@ def image(self, img: Optional[str], frame: Optional[int], blink: bool = False): imwidth, imheight = img.size if imwidth != self.width or imheight != self.height: raise ValueError( - f"Image must be same dimensions as display {self.width}x{self.height}" + "Image must be same dimensions as display ({0}x{1}).".format( + self.width, self.height + ) ) # Grab all the pixels from the image, faster than getpixel. pixels = img.load() From d4e54c9a50ce4c1cbb1fd66934b4dc785b8b372a Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Mon, 15 Apr 2024 02:13:24 -0400 Subject: [PATCH 26/33] check for linux if attempting to use PIL --- adafruit_is31fl3731/matrix.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/adafruit_is31fl3731/matrix.py b/adafruit_is31fl3731/matrix.py index 5e5b927..1c62526 100644 --- a/adafruit_is31fl3731/matrix.py +++ b/adafruit_is31fl3731/matrix.py @@ -30,10 +30,15 @@ from . import IS31FL3731 try: - from typing import TYPE_CHECKING, Optional, Image + from typing import TYPE_CHECKING, Optional if TYPE_CHECKING: from circuitpython_typing import ReadableBuffer + + import sys + + if sys.platform == "linux": + from PIL import Image except ImportError as e: pass From b5b921af846cbc4c86fa43466372031338ad6d57 Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Mon, 15 Apr 2024 02:17:03 -0400 Subject: [PATCH 27/33] trying different import order --- adafruit_is31fl3731/matrix.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adafruit_is31fl3731/matrix.py b/adafruit_is31fl3731/matrix.py index 1c62526..4418ecc 100644 --- a/adafruit_is31fl3731/matrix.py +++ b/adafruit_is31fl3731/matrix.py @@ -27,8 +27,6 @@ """ # imports -from . import IS31FL3731 - try: from typing import TYPE_CHECKING, Optional @@ -42,6 +40,8 @@ except ImportError as e: pass +from . import IS31FL3731 + class Matrix(IS31FL3731): """Charlieplexed Featherwing & IS31FL3731 I2C Modules""" From cbdf431e65f284bce955bf8fc84be0ed01075c11 Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Mon, 15 Apr 2024 02:32:23 -0400 Subject: [PATCH 28/33] pil is pil.py not pillow? --- adafruit_is31fl3731/matrix.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/adafruit_is31fl3731/matrix.py b/adafruit_is31fl3731/matrix.py index 4418ecc..f77f6a2 100644 --- a/adafruit_is31fl3731/matrix.py +++ b/adafruit_is31fl3731/matrix.py @@ -27,21 +27,17 @@ """ # imports +from . import IS31FL3731 +from .pil import Image # Import Image from the pil module + try: from typing import TYPE_CHECKING, Optional if TYPE_CHECKING: from circuitpython_typing import ReadableBuffer - - import sys - - if sys.platform == "linux": - from PIL import Image except ImportError as e: pass -from . import IS31FL3731 - class Matrix(IS31FL3731): """Charlieplexed Featherwing & IS31FL3731 I2C Modules""" From 251155c81fa1e60641968bc542a421ad6920b5a3 Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Mon, 15 Apr 2024 02:35:57 -0400 Subject: [PATCH 29/33] pil Image is part of circuitpython_typing? --- adafruit_is31fl3731/matrix.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/adafruit_is31fl3731/matrix.py b/adafruit_is31fl3731/matrix.py index f77f6a2..1a52972 100644 --- a/adafruit_is31fl3731/matrix.py +++ b/adafruit_is31fl3731/matrix.py @@ -28,7 +28,9 @@ # imports from . import IS31FL3731 -from .pil import Image # Import Image from the pil module +from .circuitpython_typing.pil import ( + Image, +) # Import Image from the pil module within circuitpython_typing try: from typing import TYPE_CHECKING, Optional From c56891c3b3cb2f575354efeb952ff1cecf852097 Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Mon, 15 Apr 2024 02:44:04 -0400 Subject: [PATCH 30/33] can i make all the things optional? --- adafruit_is31fl3731/matrix.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/adafruit_is31fl3731/matrix.py b/adafruit_is31fl3731/matrix.py index 1a52972..1e1aca0 100644 --- a/adafruit_is31fl3731/matrix.py +++ b/adafruit_is31fl3731/matrix.py @@ -28,15 +28,10 @@ # imports from . import IS31FL3731 -from .circuitpython_typing.pil import ( - Image, -) # Import Image from the pil module within circuitpython_typing try: - from typing import TYPE_CHECKING, Optional - - if TYPE_CHECKING: - from circuitpython_typing import ReadableBuffer + from typing import Optional + from circuitpython_typing import Image except ImportError as e: pass From 72a3262338a4a7e87c9e36681602f8274643b7d1 Mon Sep 17 00:00:00 2001 From: DJDevon3 <49322231+DJDevon3@users.noreply.github.com> Date: Mon, 15 Apr 2024 02:57:33 -0400 Subject: [PATCH 31/33] Welcome to Costco, I love you. --- adafruit_is31fl3731/matrix.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/adafruit_is31fl3731/matrix.py b/adafruit_is31fl3731/matrix.py index 1e1aca0..79386d8 100644 --- a/adafruit_is31fl3731/matrix.py +++ b/adafruit_is31fl3731/matrix.py @@ -31,7 +31,9 @@ try: from typing import Optional - from circuitpython_typing import Image + + # Define a placeholder for Image if it's not available + IMAGE = None except ImportError as e: pass @@ -54,7 +56,7 @@ def pixel_addr(x: int, y: int) -> int: # for animation. Buffering the full matrix for a quick write is not a # memory concern here, as by definition this method is used with PIL # images; we're not running on a RAM-constrained microcontroller. - def image(self, img: Optional[Image], frame: Optional[int], blink: bool = False): + def image(self, img: Optional[IMAGE], frame: Optional[int], blink: bool = False): """Set buffer to value of Python Imaging Library image. The image should be in 8-bit mode (L) and a size equal to the display size. From c2af4be0588fb7ea26fe1dc71e9edf43ed0fbe92 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 13 May 2024 11:40:22 -0500 Subject: [PATCH 32/33] typing tweaks --- adafruit_is31fl3731/__init__.py | 28 ++++++++++++++++------------ adafruit_is31fl3731/matrix.py | 9 ++++++--- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/adafruit_is31fl3731/__init__.py b/adafruit_is31fl3731/__init__.py index 31539cd..01ae103 100644 --- a/adafruit_is31fl3731/__init__.py +++ b/adafruit_is31fl3731/__init__.py @@ -111,7 +111,7 @@ class IS31FL3731: :param ~busio.I2C i2c: the connected i2c bus i2c_device :param int address: the device address; defaults to 0x74 - :param int frames: static 0 or animation frames (0-7) + :param Iterable frames: list of frame indexes to use. int's 0-7. """ width: int = 16 @@ -120,14 +120,16 @@ class IS31FL3731: def __init__( self, i2c: busio.I2C, - frames: Optional[int] = None, + frames: Optional[Iterable] = None, address: int = 0x74, ): self.i2c_device = I2CDevice(i2c, address) self._frame = None self._init(frames=frames) - def _i2c_read_reg(self, reg: Optional[int] = None, result: Optional[int] = None): + def _i2c_read_reg( + self, reg: Optional[int] = None, result: Optional[WriteableBuffer] = None + ) -> Optional[WriteableBuffer]: # Read a buffer of data from the specified 8-bit I2C register address. # The provided result parameter will be filled to capacity with bytes # of data read from the register. @@ -190,13 +192,13 @@ def _init(self, frames: Iterable) -> None: self._frame = 0 # To match config bytes above self.sleep(False) - def reset(self): + def reset(self) -> None: """Kill the display for 10MS""" self.sleep(True) time.sleep(0.01) # 10 MS pause to reset. self.sleep(False) - def sleep(self, value): + def sleep(self, value: bool) -> Optional[int]: """ Set the Software Shutdown Register bit @@ -206,10 +208,10 @@ def sleep(self, value): def autoplay( self, - delay: Optional[int] = None, - loops: Optional[Iterable] = None, - frames: Optional[int] = None, - ) -> int: + delay: int = 0, + loops: int = 0, + frames: int = 0, + ) -> None: """ Start autoplay @@ -235,7 +237,7 @@ def fade( self, fade_in: Optional[int] = None, fade_out: Optional[int] = None, - pause: Optional[int] = None, + pause: int = 0, ) -> int: """ Start and stop the fade feature. If both fade_in and fade_out are None (the @@ -314,7 +316,7 @@ def audio_play( ) self._mode(_AUDIOPLAY_MODE) - def blink(self, rate: Optional[int]) -> Optional[int]: + def blink(self, rate: Optional[int] = None) -> Optional[int]: """Updates the blink register""" # pylint: disable=no-else-return # This needs to be refactored when it can be tested @@ -435,7 +437,9 @@ def pixel( # pylint: enable-msg=too-many-arguments - def image(self, img: Optional[str], frame: Optional[int], blink: bool = False): + def image( + self, img: Image, frame: Optional[int] = None, blink: bool = False + ) -> None: """Set buffer to value of Python Imaging Library image. The image should be in 8-bit mode (L) and a size equal to the display size. diff --git a/adafruit_is31fl3731/matrix.py b/adafruit_is31fl3731/matrix.py index 79386d8..73a2409 100644 --- a/adafruit_is31fl3731/matrix.py +++ b/adafruit_is31fl3731/matrix.py @@ -32,8 +32,11 @@ try: from typing import Optional - # Define a placeholder for Image if it's not available - IMAGE = None + try: + from PIL import Image + except ImportError: + # placeholder if PIL unavailable + Image = None except ImportError as e: pass @@ -56,7 +59,7 @@ def pixel_addr(x: int, y: int) -> int: # for animation. Buffering the full matrix for a quick write is not a # memory concern here, as by definition this method is used with PIL # images; we're not running on a RAM-constrained microcontroller. - def image(self, img: Optional[IMAGE], frame: Optional[int], blink: bool = False): + def image(self, img: Image, frame: Optional[int] = None, blink: bool = False): """Set buffer to value of Python Imaging Library image. The image should be in 8-bit mode (L) and a size equal to the display size. From 9cf72647652f483f3f0f5ceb79f6c3ffe8bd0b53 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 13 May 2024 11:53:34 -0500 Subject: [PATCH 33/33] add PIL to optional reqs --- optional_requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/optional_requirements.txt b/optional_requirements.txt index dcabec4..afdd721 100644 --- a/optional_requirements.txt +++ b/optional_requirements.txt @@ -3,3 +3,4 @@ # SPDX-License-Identifier: Unlicense adafruit-circuitpython-framebuf +pillow